diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index b593cd5f8219..3b450f5d0790 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -164,6 +164,10 @@ public: ak_nestednamespec, // NestedNameSpecifier * ak_declcontext // DeclContext * }; + + /// ArgumentValue - This typedef represents on argument value, which is a + /// union discriminated by ArgumentKind, with a value. + typedef std::pair ArgumentValue; private: unsigned char AllExtensionsSilenced; // Used by __extension__ @@ -203,10 +207,17 @@ private: /// ArgToStringFn - A function pointer that converts an opaque diagnostic /// argument to a strings. This takes the modifiers and argument that was /// present in the diagnostic. + /// + /// The PrevArgs array (whose length is NumPrevArgs) indicates the previous + /// arguments formatted for this diagnostic. Implementations of this function + /// can use this information to avoid redundancy across arguments. + /// /// This is a hack to avoid a layering violation between libbasic and libsema. typedef void (*ArgToStringFnTy)(ArgumentKind Kind, intptr_t Val, const char *Modifier, unsigned ModifierLen, const char *Argument, unsigned ArgumentLen, + const ArgumentValue *PrevArgs, + unsigned NumPrevArgs, llvm::SmallVectorImpl &Output, void *Cookie); void *ArgToStringCookie; @@ -311,9 +322,10 @@ public: void ConvertArgToString(ArgumentKind Kind, intptr_t Val, const char *Modifier, unsigned ModLen, const char *Argument, unsigned ArgLen, + const ArgumentValue *PrevArgs, unsigned NumPrevArgs, llvm::SmallVectorImpl &Output) const { - ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, Output, - ArgToStringCookie); + ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, + PrevArgs, NumPrevArgs, Output, ArgToStringCookie); } void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index d3bb9d5496cb..d665e49126d3 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -190,6 +190,8 @@ namespace clang { static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, const char *Modifier, unsigned ML, const char *Argument, unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, llvm::SmallVectorImpl &Output, void *Cookie) { const char *Str = ""; @@ -685,6 +687,12 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { const char *DiagStr = getDiags()->getDescription(getID()); const char *DiagEnd = DiagStr+strlen(DiagStr); + /// FormattedArgs - Keep track of all of the arguments formatted by + /// ConvertArgToString and pass them into subsequent calls to + /// ConvertArgToString, allowing the implementation to avoid redundancies in + /// obvious cases. + llvm::SmallVector FormattedArgs; + while (DiagStr != DiagEnd) { if (DiagStr[0] != '%') { // Append non-%0 substrings to Str if we have one. @@ -732,7 +740,9 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic"); unsigned ArgNo = *DiagStr++ - '0'; - switch (getArgKind(ArgNo)) { + Diagnostic::ArgumentKind Kind = getArgKind(ArgNo); + + switch (Kind) { // ---- STRINGS ---- case Diagnostic::ak_std_string: { const std::string &S = getArgStdStr(ArgNo); @@ -802,11 +812,23 @@ FormatDiagnostic(llvm::SmallVectorImpl &OutStr) const { case Diagnostic::ak_nameddecl: case Diagnostic::ak_nestednamespec: case Diagnostic::ak_declcontext: - getDiags()->ConvertArgToString(getArgKind(ArgNo), getRawArg(ArgNo), + getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo), Modifier, ModifierLen, - Argument, ArgumentLen, OutStr); + Argument, ArgumentLen, + FormattedArgs.data(), FormattedArgs.size(), + OutStr); break; } + + // Remember this argument info for subsequent formatting operations. Turn + // std::strings into a null terminated string to make it be the same case as + // all the other ones. + if (Kind != Diagnostic::ak_std_string) + FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo))); + else + FormattedArgs.push_back(std::make_pair(Diagnostic::ak_c_string, + (intptr_t)getArgStdStr(ArgNo).c_str())); + } } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 6e9362f28c29..1cb0dcf02b06 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -148,6 +148,8 @@ static std::string ConvertTypeToDiagnosticString(ASTContext &Context, static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, const char *Modifier, unsigned ModLen, const char *Argument, unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, llvm::SmallVectorImpl &Output, void *Cookie) { ASTContext &Context = *static_cast(Cookie);