]> granicus.if.org Git - clang/commitdiff
Recover properly from a redundant 'typename' before a non-nested name. This is
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 14 May 2012 22:43:34 +0000 (22:43 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 14 May 2012 22:43:34 +0000 (22:43 +0000)
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

lib/Parse/Parser.cpp
test/Parser/MicrosoftExtensions.cpp

index 955f4558f8505390f0f3966e94ed9e0180b51f9f..ad283fa57a68dc692edccf788087d80810db458e 100644 (file)
@@ -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;
     }
 
index 3a1ffea453caa925e312016fef8aa27fff23597b..351fa73588f359aa610b6a1c0e38cbae97d6993e 100644 (file)
@@ -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'}}
 }