[cfe-commits] r59871 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Basic/Diagnostic.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/copy-initialization.cpp test/SemaCXX/overloaded-operator.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sat Nov 22 05:44:37 PST 2008


Author: cornedbee
Date: Sat Nov 22 07:44:36 2008
New Revision: 59871

URL: http://llvm.org/viewvc/llvm-project?rev=59871&view=rev
Log:
Implement a %plural modifier for complex plural forms in diagnostics. Use it in the overload diagnostics.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/lib/Basic/Diagnostic.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/copy-initialization.cpp
    cfe/trunk/test/SemaCXX/overloaded-operator.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=59871&r1=59870&r2=59871&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Sat Nov 22 07:44:36 2008
@@ -873,11 +873,11 @@
 DIAG(err_ovl_diff_return_type, ERROR,
      "functions that differ only in their return type cannot be overloaded")
 DIAG(err_ovl_static_nonstatic_member, ERROR,
-     "static and non-static member functions with the same parameter types cannot be overloaded")
+     "static and non-static member functions with the same parameter types "
+     "cannot be overloaded")
 DIAG(err_ovl_no_viable_function_in_call, ERROR,
-     "no matching function for call to '%0'.")
-DIAG(err_ovl_no_viable_function_in_call_with_cands, ERROR,
-     "no matching function for call to '%0'; candidates are:")
+     "no matching function for call to '%0'"
+     "%plural{0:.|1:; candidate is|:; candidates are:}1")
 DIAG(err_ovl_ambiguous_call, ERROR,
      "call to '%0' is ambiguous; candidates are:")
 DIAG(err_ovl_candidate, NOTE,
@@ -885,19 +885,17 @@
 DIAG(err_ovl_builtin_candidate, NOTE,
      "built-in candidate function '%0'")
 DIAG(err_ovl_no_viable_function_in_init, ERROR,
-     "no matching constructor for initialization of '%0'.")
-DIAG(err_ovl_no_viable_function_in_init_with_cands, ERROR,
-     "no matching constructor for initialization of '%0'; candidates are:")
+     "no matching constructor for initialization of '%0'"
+     "%plural{0:.|1:; candidate is|:; candidates are:}1")
 DIAG(err_ovl_ambiguous_init, ERROR,
      "call to constructor of '%0' is ambiguous; candidates are:")
 DIAG(err_ovl_ambiguous_oper, ERROR,
      "use of overloaded operator '%0' is ambiguous; candidates are:")
 DIAG(err_ovl_no_viable_oper, ERROR,
-     "no viable overloaded '%0'; candidates are:")
+     "no viable overloaded '%0'; candidate%plural{1: is|:s are}1:")
 DIAG(err_ovl_no_viable_object_call, ERROR,
-     "no matching function for call to object of type '%0'")
-DIAG(err_ovl_no_viable_object_call_with_cands, ERROR,
-     "no matching function for call to object of type '%0'; candidates are:")
+     "no matching function for call to object of type '%0'"
+     "%plural{0:.|1:; candidate is|:; candidates are:}1")
 DIAG(err_ovl_ambiguous_object_call, ERROR,
      "call to object of type '%0' is ambiguous; candidates are:")
 DIAG(err_ovl_surrogate_cand, NOTE,

Modified: cfe/trunk/lib/Basic/Diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=59871&r1=59870&r2=59871&view=diff

==============================================================================
--- cfe/trunk/lib/Basic/Diagnostic.cpp (original)
+++ cfe/trunk/lib/Basic/Diagnostic.cpp Sat Nov 22 07:44:36 2008
@@ -293,6 +293,128 @@
 }
 
 
+/// PluralNumber - Parse an unsigned integer and advance Start.
+static unsigned PluralNumber(const char *&Start, const char *End)
+{
+  // Programming 101: Parse a decimal number :-)
+  unsigned Val = 0;
+  while (Start != End && *Start >= '0' && *Start <= '9') {
+    Val *= 10;
+    Val += *Start - '0';
+    ++Start;
+  }
+  return Val;
+}
+
+/// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
+static bool TestPluralRange(unsigned Val, const char *&Start, const char *End)
+{
+  if (*Start != '[') {
+    unsigned Ref = PluralNumber(Start, End);
+    return Ref == Val;
+  }
+
+  ++Start;
+  unsigned Low = PluralNumber(Start, End);
+  assert(*Start == ',' && "Bad plural expression syntax: expected ,");
+  ++Start;
+  unsigned High = PluralNumber(Start, End);
+  assert(*Start == ']' && "Bad plural expression syntax: expected )");
+  ++Start;
+  return Low <= Val && Val <= High;
+}
+
+/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
+static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End)
+{
+  // Empty condition?
+  if (*Start == ':')
+    return true;
+
+  while (1) {
+    char C = *Start;
+    if (C == '%') {
+      // Modulo expression
+      ++Start;
+      unsigned Arg = PluralNumber(Start, End);
+      assert(*Start == '=' && "Bad plural expression syntax: expected =");
+      ++Start;
+      unsigned ValMod = ValNo % Arg;
+      if (TestPluralRange(ValMod, Start, End))
+        return true;
+    } else {
+      assert(C == '[' || (C >= '0' && C <= '9') &&
+             "Bad plural expression syntax: unexpected character");
+      // Range expression
+      if (TestPluralRange(ValNo, Start, End))
+        return true;
+    }
+
+    // Scan for next or-expr part.
+    Start = std::find(Start, End, ',');
+    if(Start == End)
+      break;
+    ++Start;
+  }
+  return false;
+}
+
+/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
+/// for complex plural forms, or in languages where all plurals are complex.
+/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
+/// conditions that are tested in order, the form corresponding to the first
+/// that applies being emitted. The empty condition is always true, making the
+/// last form a default case.
+/// Conditions are simple boolean expressions, where n is the number argument.
+/// Here are the rules.
+/// condition  := expression | empty
+/// empty      :=                             -> always true
+/// expression := numeric [',' expression]    -> logical or
+/// numeric    := range                       -> true if n in range
+///             | '%' number '=' range        -> true if n % number in range
+/// range      := number
+///             | '[' number ',' number ']'   -> ranges are inclusive both ends
+///
+/// Here are some examples from the GNU gettext manual written in this form:
+/// English:
+/// {1:form0|:form1}
+/// Latvian:
+/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
+/// Gaeilge:
+/// {1:form0|2:form1|:form2}
+/// Romanian:
+/// {1:form0|0,%100=[1,19]:form1|:form2}
+/// Lithuanian:
+/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
+/// Russian (requires repeated form):
+/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
+/// Slovak
+/// {1:form0|[2,4]:form1|:form2}
+/// Polish (requires repeated form):
+/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
+static void HandlePluralModifier(unsigned ValNo,
+                                 const char *Argument, unsigned ArgumentLen,
+                                 llvm::SmallVectorImpl<char> &OutStr)
+{
+  const char *ArgumentEnd = Argument + ArgumentLen;
+  while (1) {
+    assert(Argument < ArgumentEnd && "Plural expression didn't match.");
+    const char *ExprEnd = Argument;
+    while (*ExprEnd != ':') {
+      assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
+      ++ExprEnd;
+    }
+    if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
+      Argument = ExprEnd + 1;
+      ExprEnd = std::find(Argument, ArgumentEnd, '|');
+      OutStr.append(Argument, ExprEnd);
+      return;
+    }
+    Argument = std::find(Argument, ArgumentEnd - 1, '|') + 1;
+  }
+}
+
+
 /// FormatDiagnostic - Format this diagnostic into a string, substituting the
 /// formal arguments into the %0 slots.  The result is appended onto the Str
 /// array.
@@ -374,6 +496,8 @@
         HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
       } else if (ModifierIs(Modifier, ModifierLen, "s")) {
         HandleIntegerSModifier(Val, OutStr);
+      } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
+        HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
       } else {
         assert(ModifierLen == 0 && "Unknown integer modifier");
         // FIXME: Optimize
@@ -389,6 +513,8 @@
         HandleSelectModifier(Val, Argument, ArgumentLen, OutStr);
       } else if (ModifierIs(Modifier, ModifierLen, "s")) {
         HandleIntegerSModifier(Val, OutStr);
+      } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
+        HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
       } else {
         assert(ModifierLen == 0 && "Unknown integer modifier");
         

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=59871&r1=59870&r2=59871&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Nov 22 07:44:36 2008
@@ -1440,13 +1440,9 @@
     return cast<CXXConstructorDecl>(Best->Function);
     
   case OR_No_Viable_Function:
-    if (CandidateSet.empty())
-      Diag(Loc, diag::err_ovl_no_viable_function_in_init) << InitEntity <<Range;
-    else {
-      Diag(Loc, diag::err_ovl_no_viable_function_in_init_with_cands)
-        << InitEntity << Range;
-      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
-    }
+    Diag(Loc, diag::err_ovl_no_viable_function_in_init)
+      << InitEntity << (unsigned)CandidateSet.size() << Range;
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
     return 0;
     
   case OR_Ambiguous:

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=59871&r1=59870&r2=59871&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Sat Nov 22 07:44:36 2008
@@ -1309,16 +1309,11 @@
       break;
 
     case OR_No_Viable_Function:
-      if (CandidateSet.empty())
-        Diag(Fn->getSourceRange().getBegin(), 
-             diag::err_ovl_no_viable_function_in_call)
-          << Ovl->getName() << Fn->getSourceRange();
-      else {
-        Diag(Fn->getSourceRange().getBegin(), 
-             diag::err_ovl_no_viable_function_in_call_with_cands)
-          << Ovl->getName() << Fn->getSourceRange();
-        PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
-      }
+      Diag(Fn->getSourceRange().getBegin(), 
+           diag::err_ovl_no_viable_function_in_call)
+        << Ovl->getName() << (unsigned)CandidateSet.size()
+        << Fn->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
       return true;
 
     case OR_Ambiguous:

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=59871&r1=59870&r2=59871&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Sat Nov 22 07:44:36 2008
@@ -3050,16 +3050,11 @@
     break;
 
   case OR_No_Viable_Function:
-    if (CandidateSet.empty())
-      Diag(Object->getSourceRange().getBegin(), 
-           diag::err_ovl_no_viable_object_call)
-        << Object->getType().getAsString() << Object->getSourceRange();
-    else {
-      Diag(Object->getSourceRange().getBegin(), 
-           diag::err_ovl_no_viable_object_call_with_cands)
-        << Object->getType().getAsString() << Object->getSourceRange();
-      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
-    }
+    Diag(Object->getSourceRange().getBegin(), 
+         diag::err_ovl_no_viable_object_call)
+      << Object->getType().getAsString() << (unsigned)CandidateSet.size()
+      << Object->getSourceRange();
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
     break;
 
   case OR_Ambiguous:
@@ -3220,7 +3215,8 @@
         << BasePtr->getType().getAsString() << BasePtr->getSourceRange();
     else
       Diag(OpLoc, diag::err_ovl_no_viable_oper)
-        << "operator->" << BasePtr->getSourceRange();
+        << "operator->" << (unsigned)CandidateSet.size()
+        << BasePtr->getSourceRange();
     PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
     return true;
 

Modified: cfe/trunk/test/SemaCXX/copy-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/copy-initialization.cpp?rev=59871&r1=59870&r2=59871&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/copy-initialization.cpp (original)
+++ cfe/trunk/test/SemaCXX/copy-initialization.cpp Sat Nov 22 07:44:36 2008
@@ -10,7 +10,7 @@
 class Y : public X { };
 
 void f(Y y, int *ip, float *fp) {
-  X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidates are:}}
+  X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidate is:}}
   X x2 = 0;
   X x3 = ip;
   X x4 = fp; // expected-error{{incompatible type initializing 'x4', expected 'class X'}}

Modified: cfe/trunk/test/SemaCXX/overloaded-operator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-operator.cpp?rev=59871&r1=59870&r2=59871&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-operator.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-operator.cpp Sat Nov 22 07:44:36 2008
@@ -170,5 +170,5 @@
 void test_arrow(Arrow1 a1, Arrow2 a2, const Arrow2 a3) {
   int &i1 = a1->m;
   int &i2 = a2->m;
-  a3->m; // expected-error{{no viable overloaded 'operator->'; candidates are}}
+  a3->m; // expected-error{{no viable overloaded 'operator->'; candidate is}}
 }





More information about the cfe-commits mailing list