Ping. Any comments on this patch?
On Fri, Apr 15, 2011 at 10:25 PM, Richard Trieu <[email protected]> wrote:
> 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