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,
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,
}
+/// 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.
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
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");
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:
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:
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:
<< 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;
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'}}
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}}
}