diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-05-14 22:43:34 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-05-14 22:43:34 +0000 |
commit | 23756776eadfd8bbddf5d120d4c191ef9e50d209 (patch) | |
tree | 82ced400d4f87ef65ec550071ad3d02676d97fd1 | |
parent | 45246a7fc00f07bba9a34a3f13c0af72a05f95be (diff) |
Recover properly from a redundant 'typename' before a non-nested name. This is
permitted as a Microsoft extension. Patch by William Wilson! (Plus some minor
tweaking by me.)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@156786 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Parse/Parser.cpp | 22 | ||||
-rw-r--r-- | test/Parser/MicrosoftExtensions.cpp | 13 |
2 files changed, 30 insertions, 5 deletions
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 955f4558f8..ad283fa57a 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1248,7 +1248,8 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) { bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope) - || Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!"); + || Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) + && "Cannot be a type or scope token!"); if (Tok.is(tok::kw_typename)) { // Parse a C++ typename-specifier, e.g., "typename T::type". @@ -1264,10 +1265,21 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { 0, /*IsTypename*/true)) return true; if (!SS.isSet()) { - if (getLangOpts().MicrosoftExt) - Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); - else - Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); + if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id)) { + // Attempt to recover by skipping the invalid 'typename' + if (!TryAnnotateTypeOrScopeToken(EnteringContext, NeedType) && + Tok.isAnnotation()) { + unsigned DiagID = diag::err_expected_qualified_after_typename; + // MS compatibility: MSVC permits using known types with typename. + // e.g. "typedef typename T* pointer_type" + if (getLangOpts().MicrosoftExt) + DiagID = diag::warn_expected_qualified_after_typename; + Diag(Tok.getLocation(), DiagID); + return false; + } + } + + Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); return true; } diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index 3a1ffea453..351fa73588 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -151,11 +151,24 @@ void missing_template_keyword(){ class AAAA { }; +template <typename T> +class SimpleTemplate {}; + template <class T> void redundant_typename() { typename T t;// expected-warning {{expected a qualified name after 'typename'}} typename AAAA a;// expected-warning {{expected a qualified name after 'typename'}} + t = 3; + + typedef typename T* pointerT;// expected-warning {{expected a qualified name after 'typename'}} + typedef typename SimpleTemplate<int> templateT;// expected-warning {{expected a qualified name after 'typename'}} + + pointerT pT = &t; + *pT = 4; + + int var; + int k = typename var;// expected-error {{expected a qualified name after 'typename'}} } |