"overloaded '%0' cannot be a static member function")
DIAG(err_operator_overload_default_arg, ERROR,
"parameter of overloaded '%0' cannot have a default argument")
-DIAG(err_operator_overload_must_be_unary, ERROR,
- "overloaded '%0' must be a unary operator (has %1 parameter)")
-DIAG(err_operator_overload_must_be_binary, ERROR,
- "overloaded '%0' must be a binary operator (has %1 parameter)")
-DIAG(err_operator_overload_must_be_unary_or_binary, ERROR,
- "overloaded '%0' must be a unary or binary operator (has %1 parameter)")
-DIAG(err_operator_overload_must_be_unary_plural, ERROR,
- "overloaded '%0' must be a unary operator (has %1 parameters)")
-DIAG(err_operator_overload_must_be_binary_plural, ERROR,
- "overloaded '%0' must be a binary operator (has %1 parameters)")
-DIAG(err_operator_overload_must_be_unary_or_binary_plural, ERROR,
- "overloaded '%0' must be a unary or binary operator (has %1 parameters)")
+DIAG(err_operator_overload_must_be_unaryx, ERROR,
+ "overloaded '%0' must be a unary operator (has %1 parameter%s1)")
+DIAG(err_operator_overload_must_be_binaryx, ERROR,
+ "overloaded '%0' must be a binary operator (has %1 parameter%s1)")
+DIAG(err_operator_overload_must_be_unary_or_binaryx, ERROR,
+ "overloaded '%0' must be a unary or binary operator (has %1 parameter%s1)")
DIAG(err_operator_overload_must_be_member, ERROR,
"overloaded '%0' must be a non-static member function")
-DIAG(err_operator_overload_post_inc_must_be_int, ERROR,
- "parameter of overloaded post-increment operator must have type 'int' "
- "(not '%0')")
-DIAG(err_operator_overload_post_dec_must_be_int, ERROR,
- "parameter of overloaded post-decrement operator must have type 'int' "
- "(not '%0')")
+DIAG(err_operator_overload_post_incdec_must_be_int, ERROR,
+ "parameter of overloaded post-%select{increment|decrement}1 operator must"
+ " have type 'int' (not '%0')")
DIAG(err_operator_missing_type_specifier, ERROR,
"missing type specifier after 'operator'")
DiagnosticClient::~DiagnosticClient() {}
+/// ModifierIs - Return true if the specified modifier matches specified string.
+template <std::size_t StrLen>
+static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
+ const char (&Str)[StrLen]) {
+ return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
+}
+
+/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
+/// like this: %select{foo|bar|baz}2. This means that the integer argument
+/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
+/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
+/// This is very useful for certain classes of variant diagnostics.
+static void HandleSelectModifier(unsigned ValNo,
+ const char *Argument, unsigned ArgumentLen,
+ llvm::SmallVectorImpl<char> &OutStr) {
+ const char *ArgumentEnd = Argument+ArgumentLen;
+
+ // Skip over 'ValNo' |'s.
+ while (ValNo) {
+ const char *NextVal = std::find(Argument, ArgumentEnd, '|');
+ assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
+ " larger than the number of options in the diagnostic string!");
+ Argument = NextVal+1; // Skip this string.
+ --ValNo;
+ }
+
+ // Get the end of the value. This is either the } or the |.
+ const char *EndPtr = std::find(Argument, ArgumentEnd, '|');
+ // Add the value to the output string.
+ OutStr.append(Argument, EndPtr);
+}
+
+/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
+/// letter 's' to the string if the value is not 1. This is used in cases like
+/// this: "you idiot, you have %4 parameter%s4!".
+static void HandleIntegerSModifier(unsigned ValNo,
+ llvm::SmallVectorImpl<char> &OutStr) {
+ if (ValNo != 1)
+ OutStr.push_back('s');
+}
+
+
/// FormatDiagnostic - Format this diagnostic into a string, substituting the
/// formal arguments into the %0 slots. The result is appended onto the Str
/// array.
const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
OutStr.append(DiagStr, StrEnd);
DiagStr = StrEnd;
+ continue;
} else if (DiagStr[1] == '%') {
OutStr.push_back('%'); // %% -> %.
DiagStr += 2;
- } else {
- assert(isdigit(DiagStr[1]) && "Must escape % with %%");
- unsigned StrNo = DiagStr[1] - '0';
+ continue;
+ }
+
+ // Skip the %.
+ ++DiagStr;
+
+ // This must be a placeholder for a diagnostic argument. The format for a
+ // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
+ // The digit is a number from 0-9 indicating which argument this comes from.
+ // The modifier is a string of digits from the set [-a-z]+, arguments is a
+ // brace enclosed string.
+ const char *Modifier = 0, *Argument = 0;
+ unsigned ModifierLen = 0, ArgumentLen = 0;
+
+ // Check to see if we have a modifier. If so eat it.
+ if (!isdigit(DiagStr[0])) {
+ Modifier = DiagStr;
+ while (DiagStr[0] == '-' ||
+ (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
+ ++DiagStr;
+ ModifierLen = DiagStr-Modifier;
- switch (getArgKind(StrNo)) {
- case DiagnosticInfo::ak_std_string: {
- const std::string &S = getArgStdStr(StrNo);
- OutStr.append(S.begin(), S.end());
- break;
- }
- case DiagnosticInfo::ak_c_string: {
- const char *S = getArgCStr(StrNo);
- OutStr.append(S, S + strlen(S));
- break;
+ // If we have an argument, get it next.
+ if (DiagStr[0] == '{') {
+ ++DiagStr; // Skip {.
+ Argument = DiagStr;
+
+ for (; DiagStr[0] != '}'; ++DiagStr)
+ assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!");
+ ArgumentLen = DiagStr-Argument;
+ ++DiagStr; // Skip }.
}
- case DiagnosticInfo::ak_sint: {
+ }
+
+ assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic");
+ unsigned StrNo = *DiagStr++ - '0';
+
+ switch (getArgKind(StrNo)) {
+ case DiagnosticInfo::ak_std_string: {
+ const std::string &S = getArgStdStr(StrNo);
+ assert(ModifierLen == 0 && "No modifiers for strings yet");
+ OutStr.append(S.begin(), S.end());
+ break;
+ }
+ case DiagnosticInfo::ak_c_string: {
+ const char *S = getArgCStr(StrNo);
+ assert(ModifierLen == 0 && "No modifiers for strings yet");
+ OutStr.append(S, S + strlen(S));
+ break;
+ }
+ case DiagnosticInfo::ak_identifierinfo: {
+ const IdentifierInfo *II = getArgIdentifier(StrNo);
+ assert(ModifierLen == 0 && "No modifiers for strings yet");
+ OutStr.append(II->getName(), II->getName() + II->getLength());
+ break;
+ }
+ case DiagnosticInfo::ak_sint: {
+ int Val = getArgSInt(StrNo);
+
+ if (ModifierIs(Modifier, ModifierLen, "select")) {
+ HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "s")) {
+ HandleIntegerSModifier(Val, OutStr);
+ } else {
+ assert(ModifierLen == 0 && "Unknown integer modifier");
// FIXME: Optimize
- std::string S = llvm::itostr(getArgSInt(StrNo));
+ std::string S = llvm::itostr(Val);
OutStr.append(S.begin(), S.end());
- break;
}
- case DiagnosticInfo::ak_uint: {
+ break;
+ }
+ case DiagnosticInfo::ak_uint: {
+ unsigned Val = getArgUInt(StrNo);
+
+ if (ModifierIs(Modifier, ModifierLen, "select")) {
+ HandleSelectModifier(Val, Argument, ArgumentLen, OutStr);
+ } else if (ModifierIs(Modifier, ModifierLen, "s")) {
+ HandleIntegerSModifier(Val, OutStr);
+ } else {
+ assert(ModifierLen == 0 && "Unknown integer modifier");
+
// FIXME: Optimize
- std::string S = llvm::utostr_32(getArgUInt(StrNo));
+ std::string S = llvm::utostr_32(Val);
OutStr.append(S.begin(), S.end());
break;
}
- case DiagnosticInfo::ak_identifierinfo: {
- const IdentifierInfo *II = getArgIdentifier(StrNo);
- OutStr.append(II->getName(), II->getName() + II->getLength());
- break;
- }
- }
- DiagStr += 2;
+ }
}
}
}
// We have the wrong number of parameters.
diag::kind DK;
if (CanBeUnaryOperator && CanBeBinaryOperator) {
- if (NumParams == 1)
- DK = diag::err_operator_overload_must_be_unary_or_binary;
- else
- DK = diag::err_operator_overload_must_be_unary_or_binary;
+ DK = diag::err_operator_overload_must_be_unary_or_binaryx;
} else if (CanBeUnaryOperator) {
- if (NumParams == 1)
- DK = diag::err_operator_overload_must_be_unary;
- else
- DK = diag::err_operator_overload_must_be_unary_plural;
- } else if (CanBeBinaryOperator) {
- if (NumParams == 1)
- DK = diag::err_operator_overload_must_be_binary;
- else
- DK = diag::err_operator_overload_must_be_binary_plural;
+ DK = diag::err_operator_overload_must_be_unaryx;
} else {
- assert(false && "All non-call overloaded operators are unary or binary!");
+ assert(CanBeBinaryOperator &&
+ "All non-call overloaded operators are unary or binary!");
+ DK = diag::err_operator_overload_must_be_binaryx;
}
return Diag(FnDecl->getLocation(), DK) << FnDecl->getName() << NumParams;
if (const BuiltinType *BT = LastParam->getType()->getAsBuiltinType())
ParamIsInt = BT->getKind() == BuiltinType::Int;
- if (!ParamIsInt) {
- diag::kind DK;
- if (Op == OO_PlusPlus)
- DK = diag::err_operator_overload_post_inc_must_be_int;
- else
- DK = diag::err_operator_overload_post_dec_must_be_int;
- return Diag(LastParam->getLocation(), DK)
- << LastParam->getType().getAsString();
- }
+ if (!ParamIsInt)
+ return Diag(LastParam->getLocation(),
+ diag::err_operator_overload_post_incdec_must_be_int)
+ << LastParam->getType().getAsString() << (Op == OO_MinusMinus);
}
return false;