Index: tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td
==================================================================
--- tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -63,10 +63,12 @@
     "unable to open file %0 for serializing diagnostics (%1)">,
     InGroup<DiagGroup<"serialized-diagnostics">>;
 
 def err_verify_missing_line : Error<
     "missing or invalid line number following '@' in expected %0">;
+def err_verify_invalid_range : Error<
+    "invalid range following '-' in expected %0">;
 def err_verify_missing_start : Error<
     "cannot find start ('{{') of expected %0">;
 def err_verify_missing_end : Error<
     "cannot find end ('}}') of expected %0">;
 def err_verify_invalid_content : Error<

Index: tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
==================================================================
--- tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -59,10 +59,20 @@
 /// the diagnostic to appear as many times as specified. Example:
 ///
 /// \code
 ///   void f(); // expected-note 2 {{previous declaration is here}}
 /// \endcode
+///
+/// Where the diagnostic is expected to occur a minimum number of times, this
+/// can be specified by appending a '+' to the number. Example:
+///
+///   void f(); // expected-note 0+ {{previous declaration is here}}
+///
+/// In this example, the diagnostic becomes optional, i.e. it will be swallowed
+/// if it occurs, but will not generate an error if it does not occur.  A range
+/// can also be specified by <n>-<m>.  As a short-hand, "one or more" can be
+/// specified simply by '+' instead of <n>.
 ///
 /// Regex matching mode may be selected by appending '-re' to type. Example:
 ///
 ///   expected-error-re
 ///
@@ -82,19 +92,20 @@
   ///
   class Directive {
   public:
     static Directive* Create(bool RegexKind, const SourceLocation &DirectiveLoc,
                              const SourceLocation &DiagnosticLoc,
-                             const std::string &Text, unsigned Count);
+                             const std::string &Text, unsigned Min,
+                             unsigned Max);
   public:
-    /// Constant representing one or more matches aka regex "+".
-    static const unsigned OneOrMoreCount =  UINT_MAX;
+    /// Constant representing n or more matches.
+    static const unsigned MaxCount = UINT_MAX;
 
     SourceLocation DirectiveLoc;
     SourceLocation DiagnosticLoc;
     const std::string Text;
-    unsigned Count;
+    unsigned Min, Max;
 
     virtual ~Directive() { }
 
     // Returns true if directive text is valid.
     // Otherwise returns false and populates E.
@@ -104,13 +115,13 @@
     virtual bool Match(const std::string &S) = 0;
 
   protected:
     Directive(const SourceLocation &DirectiveLoc,
               const SourceLocation &DiagnosticLoc,
-              const std::string &Text, unsigned Count)
+              const std::string &Text, unsigned Min, unsigned Max)
       : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
-        Text(Text), Count(Count) { }
+        Text(Text), Min(Min), Max(Max) { }
 
   private:
     Directive(const Directive&); // DO NOT IMPLEMENT
     void operator=(const Directive&); // DO NOT IMPLEMENT
   };

Index: tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
==================================================================
--- tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -83,12 +83,12 @@
 ///
 class StandardDirective : public Directive {
 public:
   StandardDirective(const SourceLocation &DirectiveLoc,
                     const SourceLocation &DiagnosticLoc,
-                    const std::string &Text, unsigned Count)
-    : Directive(DirectiveLoc, DiagnosticLoc, Text, Count) { }
+                    const std::string &Text, unsigned Min, unsigned Max)
+    : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max) { }
 
   virtual bool isValid(std::string &Error) {
     // all strings are considered valid; even empty ones
     return true;
   }
@@ -102,12 +102,12 @@
 ///
 class RegexDirective : public Directive {
 public:
   RegexDirective(const SourceLocation &DirectiveLoc,
                  const SourceLocation &DiagnosticLoc,
-                 const std::string &Text, unsigned Count)
-    : Directive(DirectiveLoc, DiagnosticLoc, Text, Count), Regex(Text) { }
+                 const std::string &Text, unsigned Min, unsigned Max)
+    : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(Text) { }
 
   virtual bool isValid(std::string &Error) {
     if (Regex.isValid(Error))
       return true;
     return false;
@@ -264,15 +264,33 @@
 
     // Skip optional whitespace
     PH.SkipWhitespace();
 
     // Next optional token: positive integer or a '+'.
-    unsigned Count = 1;
-    if (PH.Next(Count))
+    unsigned Min = 1;
+    unsigned Max = 1;
+    if (PH.Next(Min)) {
       PH.Advance();
-    else if (PH.Next("+")) {
-      Count = Directive::OneOrMoreCount;
+      // A positive integer can be followed by a '+' meaning min
+      // or more, or by a '-' meaning a range from min to max.
+      if (PH.Next("+")) {
+        Max = Directive::MaxCount;
+        PH.Advance();
+      } else if (PH.Next("-")) {
+        PH.Advance();
+        if (!PH.Next(Max) || Max < Min) {
+          Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
+                       diag::err_verify_invalid_range) << KindStr;
+          continue;
+        }
+        PH.Advance();
+      } else {
+        Max = Min;
+      }
+    } else if (PH.Next("+")) {
+      // '+' on its own means "1 or more"
+      Max = Directive::MaxCount;
       PH.Advance();
     }
 
     // Skip optional whitespace
     PH.SkipWhitespace();
@@ -308,11 +326,12 @@
     }
     if (Text.empty())
       Text.assign(ContentBegin, ContentEnd);
 
     // Construct new directive
-    Directive *D = Directive::Create(RegexKind, Pos, ExpectedLoc, Text, Count);
+    Directive *D = Directive::Create(RegexKind, Pos, ExpectedLoc, Text,
+                                     Min, Max);
     std::string Error;
     if (D->isValid(Error))
       DL->push_back(D);
     else {
       Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
@@ -416,13 +435,12 @@
   DiagList Right(d2_begin, d2_end);
 
   for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
     Directive& D = **I;
     unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
-    bool FoundOnce = false;
 
-    for (unsigned i = 0; i < D.Count; ++i) {
+    for (unsigned i = 0; i < D.Max; ++i) {
       DiagList::iterator II, IE;
       for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
         unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
         if (LineNo1 != LineNo2)
           continue;
@@ -430,22 +448,16 @@
         const std::string &RightText = II->second;
         if (D.Match(RightText))
           break;
       }
       if (II == IE) {
-        if (D.Count == D.OneOrMoreCount) {
-          if (!FoundOnce)
-            LeftOnly.push_back(*I);
-          // We are only interested in at least one match, so exit the loop.
-          break;
-        }
         // Not found.
+        if (i >= D.Min) break;
         LeftOnly.push_back(*I);
       } else {
         // Found. The same cannot be found twice.
         Right.erase(II);
-        FoundOnce = true;
       }
     }
   }
   // Now all that's left in Right are those that were not matched.
   unsigned num = PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true);
@@ -536,10 +548,11 @@
   return new VerifyDiagnosticConsumer(Diags);
 }
 
 Directive* Directive::Create(bool RegexKind, const SourceLocation &DirectiveLoc,
                              const SourceLocation &DiagnosticLoc,
-                             const std::string &Text, unsigned Count) {
+                             const std::string &Text, unsigned Min,
+                             unsigned Max) {
   if (RegexKind)
-    return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Count);
-  return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Count);
+    return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
+  return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
 }

