See http://llvm.org/bugs/show_bug.cgi?id=9548
When two different types has the same text representation in the same
diagnostic message, print an a.k.a. after the type if the a.k.a. gives extra
information about the type.
class versa_string;
typedef versa_string string;
namespace std {template <typename T> class vector;}
using std::vector;
void f(vector<string> v);
namespace std {
class basic_string;
typedef basic_string string;
template <typename T> class vector {};
void g() {
vector<string> v;
f(v);
}
}
Old message:
----------------
test.cc:15:3: error: no matching function for call to 'f'
f(&v);
^
test.cc:7:6: note: candidate function not viable: no known conversion from
'vector<string>' to 'vector<string>' for 1st argument
void f(vector<string> v);
^
1 error generated.
New message:
---------------
test.cc:15:3: error: no matching function for call to 'f' f(v); ^
test.cc:7:6: 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 void f(vector<string> v);
^ 1 error generated.
Index: test/Misc/diag-aka-types.cpp
===================================================================
--- test/Misc/diag-aka-types.cpp (revision 129616)
+++ test/Misc/diag-aka-types.cpp (working copy)
@@ -12,3 +12,41 @@
// 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'}}
+ }
+}
Index: include/clang/Basic/Diagnostic.h
===================================================================
--- include/clang/Basic/Diagnostic.h (revision 129616)
+++ include/clang/Basic/Diagnostic.h (working copy)
@@ -121,16 +121,17 @@
};
enum ArgumentKind {
- ak_std_string, // std::string
- ak_c_string, // const char *
- ak_sint, // int
- ak_uint, // unsigned
- ak_identifierinfo, // IdentifierInfo
- ak_qualtype, // QualType
- ak_declarationname, // DeclarationName
- ak_nameddecl, // NamedDecl *
- ak_nestednamespec, // NestedNameSpecifier *
- ak_declcontext // DeclContext *
+ ak_std_string, // std::string
+ ak_c_string, // const char *
+ ak_sint, // int
+ ak_uint, // unsigned
+ ak_identifierinfo, // IdentifierInfo
+ ak_qualtype, // QualType
+ ak_qualtypeforceaka, // Force an aka when printing this Qualtype
+ ak_declarationname, // DeclarationName
+ ak_nameddecl, // NamedDecl *
+ ak_nestednamespec, // NestedNameSpecifier *
+ ak_declcontext // DeclContext *
};
/// Specifies which overload candidates to display when overload resolution
@@ -714,6 +715,23 @@
/// return Diag(...);
operator bool() const { return true; }
+ unsigned getNumArgs() const { return NumArgs; }
+
+ unsigned char getDiagArgKind(unsigned index) const {
+ assert(index < NumArgs && "Invalid index to DiagArgumentsKind");
+ return DiagObj->DiagArgumentsKind[index];
+ }
+
+ intptr_t getDiagArgVal(unsigned index) const {
+ assert(index < NumArgs && "Invalid index to DiagArgumentsVal");
+ return DiagObj->DiagArgumentsVal[index];
+ }
+
+ void setDiagArgKind(unsigned index, Diagnostic::ArgumentKind Kind) const {
+ assert(index < NumArgs && "Invalid index to DiagArgumentsKind");
+ DiagObj->DiagArgumentsKind[index] = Kind;
+ }
+
void AddString(llvm::StringRef S) const {
assert(NumArgs < Diagnostic::MaxArguments &&
"Too many arguments to diagnostic!");
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h (revision 129616)
+++ include/clang/AST/Type.h (working copy)
@@ -4319,11 +4319,54 @@
}
/// Insertion operator for diagnostics. This allows sending QualType's into a
-/// diagnostic with <<.
+/// diagnostic with <<. Include checking for QualTypes will identical names
+/// and force them to return extended information when printed if possible.
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
QualType T) {
- DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
- Diagnostic::ak_qualtype);
+ int NumArgs = DB.getNumArgs();
+ intptr_t QualTypeVal = reinterpret_cast<intptr_t>(T.getAsOpaquePtr());
+ Diagnostic::ArgumentKind NewArgKind = Diagnostic::ak_qualtype;
+
+ // Compare this QualType against all previous arguments to this diagnositic.
+ for (int i = 0; i < NumArgs; ++i) {
+ unsigned char Kind = DB.getDiagArgKind(i);
+ // Only care about QualType arguments.
+ if (Kind != Diagnostic::ak_qualtype &&
+ Kind != Diagnostic::ak_qualtypeforceaka) {
+ continue;
+ }
+ intptr_t DiagArgVal = DB.getDiagArgVal(i);
+ // Ignore if two QualTypes are the same.
+ if (DiagArgVal == QualTypeVal) {
+ continue;
+ }
+ QualType ArgTy = QualType::getFromOpaquePtr(
+ reinterpret_cast<void*>(DiagArgVal));
+ QualType ArgCanTy = ArgTy.getCanonicalType();
+ QualType CanTy = T.getCanonicalType();
+ // If the QualType names are the same and the Canonical types differ, then
+ // there exists an alternate text that will differentiate them. Mark so
+ // that the printer will output them.
+ // FIXME: Some pairs of different types will not have improved messages
+ // with printing the canonical types. For instance:
+ // int test (struct A * a1) {
+ // struct A {int x} * a2;
+ // if (a1 == a2) return 1;
+ // return 0;
+ // }
+ // gives error "comparison of distinct pointer types ('struct A *' and
+ // 'struct A *')"
+ // Both 'struct A *' have Canonical type representation of 'A *'
+ // In these cases, the extra AKA would not be printed because it does not
+ // improve the message.
+ if (CanTy != ArgCanTy && T.getAsString() == ArgTy.getAsString() &&
+ CanTy.getAsString() != ArgCanTy.getAsString()) {
+ DB.setDiagArgKind(i, Diagnostic::ak_qualtypeforceaka);
+ NewArgKind = Diagnostic::ak_qualtypeforceaka;
+ }
+ }
+
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()), NewArgKind);
return DB;
}
Index: lib/Basic/Diagnostic.cpp
===================================================================
--- lib/Basic/Diagnostic.cpp (revision 129616)
+++ lib/Basic/Diagnostic.cpp (working copy)
@@ -624,6 +624,7 @@
break;
}
case Diagnostic::ak_qualtype:
+ case Diagnostic::ak_qualtypeforceaka:
case Diagnostic::ak_declarationname:
case Diagnostic::ak_nameddecl:
case Diagnostic::ak_nestednamespec:
Index: lib/AST/ASTDiagnostic.cpp
===================================================================
--- lib/AST/ASTDiagnostic.cpp (revision 129616)
+++ lib/AST/ASTDiagnostic.cpp (working copy)
@@ -127,7 +127,7 @@
/// \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
@@ -140,13 +140,17 @@
/// 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 ForceAKA if desugaring gives more information, output it as an a.k.a.
static std::string
ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
const Diagnostic::ArgumentValue *PrevArgs,
- unsigned NumPrevArgs) {
+ unsigned NumPrevArgs, bool ForceAKA) {
// FIXME: Playing with std::string is really slow.
std::string S = Ty.getAsString(Context.PrintingPolicy);
@@ -170,11 +174,15 @@
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;
+ }
}
}
@@ -199,12 +207,14 @@
switch (Kind) {
default: assert(0 && "unknown ArgumentKind");
+ case Diagnostic::ak_qualtypeforceaka:
case Diagnostic::ak_qualtype: {
assert(ModLen == 0 && ArgLen == 0 &&
"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,
+ Kind == Diagnostic::ak_qualtypeforceaka);
NeedQuotes = false;
break;
}
@@ -255,7 +265,8 @@
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
S = ConvertTypeToDiagnosticString(Context,
Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs);
+ PrevArgs, NumPrevArgs,
+ /*ForceAKA*/false);
} else {
// FIXME: Get these strings from some localized place
NamedDecl *ND = cast<NamedDecl>(DC);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits