зеркало из https://github.com/microsoft/clang.git
Implement a %plural modifier for complex plural forms in diagnostics. Use it in the overload diagnostics.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59871 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
369f42971b
Коммит
e4c452c4c7
|
@ -873,11 +873,11 @@ DIAG(err_first_label, ERROR,
|
|||
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_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,
|
||||
|
|
|
@ -293,6 +293,128 @@ static void HandleIntegerSModifier(unsigned ValNo,
|
|||
}
|
||||
|
||||
|
||||
/// 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 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
|
|||
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 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
|
|||
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");
|
||||
|
||||
|
|
|
@ -1440,13 +1440,9 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
|
|||
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:
|
||||
|
|
|
@ -1309,16 +1309,11 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
|
|||
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:
|
||||
|
|
|
@ -3050,16 +3050,11 @@ Sema::BuildCallToObjectOfClassType(Expr *Object, SourceLocation LParenLoc,
|
|||
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 @@ Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc,
|
|||
<< 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;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ public:
|
|||
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'}}
|
||||
|
|
|
@ -170,5 +170,5 @@ struct Arrow2 {
|
|||
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}}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче