summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Basic/Diagnostic.cpp146
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp32
2 files changed, 130 insertions, 48 deletions
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index a25a790352e..e83d4f37415 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -249,6 +249,48 @@ void Diagnostic::ProcessDiag(const DiagnosticInfo &Info) {
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.
@@ -263,43 +305,97 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
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;
+ }
}
}
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 2368bc65104..f4a95f05319 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1874,22 +1874,13 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// 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;
@@ -1925,15 +1916,10 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
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;
OpenPOWER on IntegriCloud