]> granicus.if.org Git - clang/commitdiff
Apply patch from Richard Trieu to fix PR9548:
authorChandler Carruth <chandlerc@gmail.com>
Mon, 11 Jul 2011 17:49:21 +0000 (17:49 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Mon, 11 Jul 2011 17:49:21 +0000 (17:49 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134904 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTDiagnostic.h
include/clang/Basic/Diagnostic.h
lib/AST/ASTDiagnostic.cpp
lib/Basic/Diagnostic.cpp
test/Misc/diag-aka-types.cpp

index 1cb803a3396a42f74e6bb2fed78633c58c20199e..70a548d4e965a640868b4bbe422ca2f4c156e20c 100644 (file)
@@ -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
index 3b3ee4d4b0ce22fd072de98da2174feea8286641..6f72976bfcf06a77607a417f7800dd89f0db8042 100644 (file)
@@ -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) {
index 16d2f853606e094d38f48b13038b0102744e463c..7c91b5cb7a001caa7f142756bae4597399601dff 100644 (file)
@@ -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);
index e0ef53d00de630eb41e95950967297f19536842a..ae363a0df0d02fcde0be6516f9132b07006b792a 100644 (file)
@@ -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;
     }
     
index e0e6b8c7c7af49caff9ed0d5639e02aaecf62696..042c70b18a75d3e60ac844527c46ce7ce3e25f65 100644 (file)
@@ -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'}}
+  }
+}