[PATCH] Avoid spurious error messages if parent template class cannot be instantiated

Serge Pavlov sepavloff at gmail.com
Mon Jul 8 07:29:44 PDT 2013


  Fixed placement of curly brace.

Hi rsmith,

http://llvm-reviews.chandlerc.com/D924

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D924?vs=2311&id=2716#toc

Files:
  include/clang/Parse/Parser.h
  lib/Parse/ParseDeclCXX.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Parse/Parser.cpp
  test/Parser/cxx-template-argument.cpp
  test/SemaCXX/class.cpp

Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -764,6 +764,17 @@
   /// point for skipping past a simple-declaration.
   void SkipMalformedDecl();
 
+  /// \brief Discards tokens of template argument list, including closing '>'.
+  ///
+  /// The method tries to balance angle brackets pairs to skip nested template
+  /// references properly. As there is no guarantee that the brackets are
+  /// balanced, skipping will stop at points that most likely outside the
+  /// discarded argument list. The method assumes that opening '<' is already
+  /// read.
+  ///
+  /// \returns true if closing '>' is found, false otherwise.
+  bool SkipTemplateArguments();
+
 private:
   //===--------------------------------------------------------------------===//
   // Lexing and parsing of C++ inline methods.
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -918,8 +918,10 @@
         << Id;
     }
 
-    if (!Template)
+    if (!Template) {
+      SkipTemplateArguments();
       return true;
+    }
 
     // Form the template name
     UnqualifiedId TemplateName;
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -680,6 +680,8 @@
 /// \param RAngleLoc the location of the consumed '>'.
 ///
 /// \param ConsumeLastToken if true, the '>' is not consumed.
+///
+/// \returns true, if current token does not start with '>', false otherwise.
 bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
                                             bool ConsumeLastToken) {
   // What will be left once we've consumed the '>'.
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -347,6 +347,46 @@
   }
 }
 
+// Skip template arguments
+bool Parser::SkipTemplateArguments() {
+  unsigned NestingLevel = 1;
+  SourceLocation GreaterThanLoc;
+  tok::TokenKind SpecDelimiters[] = {
+      tok::less, tok::greater, tok::greatergreater, tok::greaterequal,
+      tok::greatergreaterequal, tok::greatergreatergreater};
+
+  if (Tok.is(tok::less))
+    ConsumeToken();
+  if (Tok.is(tok::semi))
+    return false;
+
+  while (Tok.isNot(tok::eof) && Tok.isNot(tok::semi)) {
+    if (SkipUntil(SpecDelimiters, /*StopAtSemi*/true, /*DontConsume*/true)) {
+      switch(Tok.getKind()) {
+      case tok::less:
+        ConsumeToken();
+        ++NestingLevel;
+        break;
+
+      case tok::greater:
+      case tok::greatergreater:
+      case tok::greaterequal:
+      case tok::greatergreaterequal:
+      case tok::greatergreatergreater:
+        ParseGreaterThanInTemplateList(GreaterThanLoc, true);
+        if (--NestingLevel == 0)
+          return true;
+        break;
+
+      default:
+        return false;
+      }
+    }
+  }
+
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // Scope manipulation
 //===----------------------------------------------------------------------===//
Index: test/Parser/cxx-template-argument.cpp
===================================================================
--- test/Parser/cxx-template-argument.cpp
+++ test/Parser/cxx-template-argument.cpp
@@ -42,3 +42,59 @@
     new C(); // expected-error {{requires template arguments}}
   }
 }
+
+// Don't emit spurious messages
+namespace pr16225add {
+
+  template<class T1, typename T2> struct Known { }; // expected-note 3 {{template is declared here}}
+  template<class T1, typename T2> struct X;
+
+  template<class T1, typename T2> struct foo :
+    UnknownBase<T1,T2> // expected-error {{unknown template name 'UnknownBase'}}
+  { };
+
+  template<class T1, typename T2> struct foo2 :
+    UnknownBase<T1,T2>, // expected-error {{unknown template name 'UnknownBase'}}
+    Known<T1>  // expected-error {{too few template arguments for class template 'Known'}}
+  { };
+
+  template<class T1, typename T2> struct foo3 :
+    UnknownBase<T1,T2,ABC<T2,T1> > // expected-error {{unknown template name 'UnknownBase'}}
+  { };
+
+  template<class T1, typename T2> struct foo4 :
+    UnknownBase<T1,ABC<T2> >, // expected-error {{unknown template name 'UnknownBase'}}
+    Known<T1>  // expected-error {{too few template arguments for class template 'Known'}}
+  { };
+
+  template<class T1, typename T2> struct foo5 :
+    UnknownBase<T1,T2,ABC<T2,T1>> // expected-error {{unknown template name 'UnknownBase'}} \
+                                  // expected-error {{use '> >'}}
+  { };
+
+  template<class T1, typename T2> struct foo6 :
+    UnknownBase<T1,ABC<T2>>, // expected-error {{unknown template name 'UnknownBase'}} \
+                             // expected-error {{use '> >'}}
+    Known<T1>  // expected-error {{too few template arguments for class template 'Known'}}
+  { };
+
+  template<class T1, typename T2, int N> struct foo7 :
+    UnknownBase<T1,T2,(N>1)> // expected-error {{unknown template name 'UnknownBase'}}
+  { };
+
+  template<class T1, typename T2> struct foo8 :
+    UnknownBase<X<int,int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}} \
+                                       // expected-error {{use '> >'}}
+  { };
+
+  template<class T1, typename T2> struct foo9 :
+    UnknownBase<Known<int>,X<int,int>> // expected-error {{unknown template name 'UnknownBase'}} \
+                                       // expected-error {{use '> >'}}
+  { };
+
+  template<class T1, typename T2> struct foo10 :
+    UnknownBase<Known<int>,X<int,X<int>>> // expected-error {{unknown template name 'UnknownBase'}} \
+                                          // expected-error {{use '> >'}}
+  { };
+
+}
Index: test/SemaCXX/class.cpp
===================================================================
--- test/SemaCXX/class.cpp
+++ test/SemaCXX/class.cpp
@@ -126,12 +126,8 @@
 
 // Don't crash on this bogus code.
 namespace pr6629 {
-  // TODO: most of these errors are spurious
   template<class T1, class T2> struct foo :
-    bogus<foo<T1,T2> > // expected-error {{unknown template name 'bogus'}} \
-                       // BOGUS expected-error {{expected '{' after base class list}} \
-                       // BOGUS expected-error {{expected ';' after struct}} \
-                       // BOGUS expected-error {{expected unqualified-id}}
+    bogus<foo<T1,T2> > // expected-error {{unknown template name 'bogus'}}
   { };
 
   template<> struct foo<unknown,unknown> { // expected-error {{undeclared identifier 'unknown'}}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D924.3.patch
Type: text/x-patch
Size: 6785 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130708/04ca648a/attachment.bin>


More information about the cfe-commits mailing list