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

Reply via email to