aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTDiagnostic.h22
-rw-r--r--include/clang/Basic/Diagnostic.h22
-rw-r--r--lib/AST/ASTDiagnostic.cpp74
-rw-r--r--lib/Basic/Diagnostic.cpp14
-rw-r--r--test/Misc/diag-aka-types.cpp38
5 files changed, 129 insertions, 41 deletions
diff --git a/include/clang/AST/ASTDiagnostic.h b/include/clang/AST/ASTDiagnostic.h
index 1cb803a339..70a548d4e9 100644
--- a/include/clang/AST/ASTDiagnostic.h
+++ b/include/clang/AST/ASTDiagnostic.h
@@ -33,16 +33,18 @@ namespace clang {
/// diagnostics. It is meant to be used as the argument to
/// \c Diagnostic::SetArgToStringFn(), where the cookie is an \c ASTContext
/// pointer.
- void FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind,
- intptr_t Val,
- const char *Modifier,
- unsigned ModLen,
- const char *Argument,
- unsigned ArgLen,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
- void *Cookie);
+ void FormatASTNodeDiagnosticArgument(
+ Diagnostic::ArgumentKind Kind,
+ intptr_t Val,
+ const char *Modifier,
+ unsigned ModLen,
+ const char *Argument,
+ unsigned ArgLen,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs,
+ llvm::SmallVectorImpl<char> &Output,
+ void *Cookie,
+ llvm::SmallVectorImpl<intptr_t> &QualTypeVals);
} // end namespace clang
#endif
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 3b3ee4d4b0..6f72976bfc 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -277,13 +277,15 @@ private:
/// 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<char> &Output,
- void *Cookie);
+ 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<char> &Output,
+ void *Cookie,
+ llvm::SmallVectorImpl<intptr_t> &QualTypeVals);
void *ArgToStringCookie;
ArgToStringFnTy ArgToStringFn;
@@ -465,9 +467,11 @@ public:
const char *Modifier, unsigned ModLen,
const char *Argument, unsigned ArgLen,
const ArgumentValue *PrevArgs, unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output) const {
+ llvm::SmallVectorImpl<char> &Output,
+ llvm::SmallVectorImpl<intptr_t> &QualTypeVals) const {
ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen,
- PrevArgs, NumPrevArgs, Output, ArgToStringCookie);
+ PrevArgs, NumPrevArgs, Output, ArgToStringCookie,
+ QualTypeVals);
}
void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) {
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 16d2f85360..7c91b5cb7a 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -129,7 +129,7 @@ break; \
/// \brief Convert the given type to a string suitable for printing as part of
/// a diagnostic.
///
-/// There are three main criteria when determining whether we should have an
+/// There are four main criteria when determining whether we should have an
/// a.k.a. clause when pretty-printing a type:
///
/// 1) Some types provide very minimal sugar that doesn't impede the
@@ -142,15 +142,44 @@ break; \
/// want to desugar these, even if we do produce an a.k.a. clause.
/// 3) Some types may have already been desugared previously in this diagnostic.
/// if this is the case, doing another "aka" would just be clutter.
+/// 4) Two different types within the same diagnostic have the same output
+/// string. In this case, force an a.k.a with the desugared type when
+/// doing so will provide additional information.
///
/// \param Context the context in which the type was allocated
/// \param Ty the type to print
+/// \param QualTypeVals pointer values to QualTypes which are used in the
+/// diagnostic message
static std::string
ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs) {
+ unsigned NumPrevArgs,
+ llvm::SmallVectorImpl<intptr_t> &QualTypeVals) {
// FIXME: Playing with std::string is really slow.
+ bool ForceAKA = false;
+ QualType CanTy = Ty.getCanonicalType();
std::string S = Ty.getAsString(Context.PrintingPolicy);
+ std::string CanS = CanTy.getAsString(Context.PrintingPolicy);
+
+ for (llvm::SmallVectorImpl<intptr_t>::iterator I = QualTypeVals.begin(),
+ E = QualTypeVals.end(); I != E; ++I) {
+ QualType CompareTy =
+ QualType::getFromOpaquePtr(reinterpret_cast<void*>(*I));
+ if (CompareTy == Ty)
+ continue; // Same types
+ QualType CompareCanTy = CompareTy.getCanonicalType();
+ if (CompareCanTy == CanTy)
+ continue; // Same canonical types
+ std::string CompareS = CompareTy.getAsString(Context.PrintingPolicy);
+ if (CompareS != S)
+ continue; // Original strings are different
+ std::string CompareCanS = CompareCanTy.getAsString(Context.PrintingPolicy);
+ if (CompareCanS == CanS)
+ continue; // No new info from canonical type
+
+ ForceAKA = true;
+ break;
+ }
// Check to see if we already desugared this type in this
// diagnostic. If so, don't do it again.
@@ -172,11 +201,15 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
if (!Repeated) {
bool ShouldAKA = false;
QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA);
- if (ShouldAKA) {
- S = "'" + S + "' (aka '";
- S += DesugaredTy.getAsString(Context.PrintingPolicy);
- S += "')";
- return S;
+ if (ShouldAKA || ForceAKA) {
+ if (DesugaredTy == Ty) {
+ DesugaredTy = Ty.getCanonicalType();
+ }
+ std::string akaStr = DesugaredTy.getAsString(Context.PrintingPolicy);
+ if (akaStr != S) {
+ S = "'" + S + "' (aka '" + akaStr + "')";
+ return S;
+ }
}
}
@@ -184,16 +217,18 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
return S;
}
-void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind,
- intptr_t Val,
- const char *Modifier,
- unsigned ModLen,
- const char *Argument,
- unsigned ArgLen,
- const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs,
- llvm::SmallVectorImpl<char> &Output,
- void *Cookie) {
+void clang::FormatASTNodeDiagnosticArgument(
+ Diagnostic::ArgumentKind Kind,
+ intptr_t Val,
+ const char *Modifier,
+ unsigned ModLen,
+ const char *Argument,
+ unsigned ArgLen,
+ const Diagnostic::ArgumentValue *PrevArgs,
+ unsigned NumPrevArgs,
+ llvm::SmallVectorImpl<char> &Output,
+ void *Cookie,
+ llvm::SmallVectorImpl<intptr_t> &QualTypeVals) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
std::string S;
@@ -206,7 +241,8 @@ void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind,
"Invalid modifier for QualType argument");
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
- S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
+ S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs,
+ QualTypeVals);
NeedQuotes = false;
break;
}
@@ -257,7 +293,7 @@ void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind,
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
S = ConvertTypeToDiagnosticString(Context,
Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs);
+ PrevArgs, NumPrevArgs, QualTypeVals);
} else {
// FIXME: Get these strings from some localized place
NamedDecl *ND = cast<NamedDecl>(DC);
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index e0ef53d00d..ae363a0df0 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -26,7 +26,8 @@ static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT,
const Diagnostic::ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
llvm::SmallVectorImpl<char> &Output,
- void *Cookie) {
+ void *Cookie,
+ llvm::SmallVectorImpl<intptr_t> &QualTypeVals) {
const char *Str = "<can't format argument>";
Output.append(Str, Str+strlen(Str));
}
@@ -544,7 +545,14 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
/// ConvertArgToString, allowing the implementation to avoid redundancies in
/// obvious cases.
llvm::SmallVector<Diagnostic::ArgumentValue, 8> FormattedArgs;
-
+
+ /// QualTypeVals - Pass a vector of arrays so that QualType names can be
+ /// compared to see if more information is needed to be printed.
+ llvm::SmallVector<intptr_t, 2> QualTypeVals;
+ for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
+ if (getArgKind(i) == Diagnostic::ak_qualtype)
+ QualTypeVals.push_back(getRawArg(i));
+
while (DiagStr != DiagEnd) {
if (DiagStr[0] != '%') {
// Append non-%0 substrings to Str if we have one.
@@ -675,7 +683,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
Modifier, ModifierLen,
Argument, ArgumentLen,
FormattedArgs.data(), FormattedArgs.size(),
- OutStr);
+ OutStr, QualTypeVals);
break;
}
diff --git a/test/Misc/diag-aka-types.cpp b/test/Misc/diag-aka-types.cpp
index e0e6b8c7c7..042c70b18a 100644
--- a/test/Misc/diag-aka-types.cpp
+++ b/test/Misc/diag-aka-types.cpp
@@ -12,3 +12,41 @@ char c2 = ref; // expected-error{{'const foo_t' (aka 'const X')}}
// deduced auto should not produce an aka.
auto aut = X();
char c3 = aut; // expected-error{{from 'X' to 'char'}}
+
+// There are two classes named Foo::foo here. Make sure the message gives
+// a way to them apart.
+namespace Foo {
+ class foo {};
+}
+
+namespace bar {
+ namespace Foo {
+ class foo;
+ }
+ void f(Foo::foo* x); // expected-note{{passing argument to parameter 'x' here}}
+}
+
+void test(Foo::foo* x) {
+ bar::f(x); // expected-error{{cannot initialize a parameter of type 'Foo::foo *' (aka 'bar::Foo::foo *') with an lvalue of type 'Foo::foo *')}}
+}
+
+// PR9548 - "no known conversion from 'vector<string>' to 'vector<string>'"
+// vector<string> refers to two different types here. Make sure the message
+// gives a way to tell them apart.
+class versa_string;
+typedef versa_string string;
+
+namespace std {template <typename T> class vector;}
+using std::vector;
+
+void f(vector<string> v); // expected-note {{candidate function not viable: no known conversion from 'vector<string>' (aka 'std::vector<std::basic_string>') to 'vector<string>' (aka 'std::vector<versa_string>') for 1st argument}}
+
+namespace std {
+ class basic_string;
+ typedef basic_string string;
+ template <typename T> class vector {};
+ void g() {
+ vector<string> v;
+ f(v); // expected-error{{no matching function for call to 'f'}}
+ }
+}