Patch to gives an error that at least points users in the direction of the error, rather 
than an error about incompatible types. Patch by Sean Hunt.

llvm-svn: 86402
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 45d6b57..84d4c59 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -3485,6 +3485,12 @@
     /// CompatiblePointerDiscardsQualifiers - The assignment discards
     /// c/v/r qualifiers, which we accept as an extension.
     CompatiblePointerDiscardsQualifiers,
+    
+    /// IncompatibleMultiPointerQualifiers - The assignment is between two
+    /// multi-level pointer types, and the qualifiers other than the first two
+    /// levels differ e.g. char ** -> const char **. We disallow this.
+    /// FIXME: GCC only warns for this - should we do the same?
+    IncompatibleMultiPointerQualifiers,
 
     /// IncompatibleVectors - The assignment is between two vector types that
     /// have the same size, which we accept as an extension.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 9a549f1..a09f6a9 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3747,6 +3747,24 @@
         return ConvTy;
       return IncompatiblePointerSign;
     }
+    
+    // If we are a multi-level pointer, it's possible that our issue is simply
+    // one of qualification - e.g. char ** -> const char ** is not allowed. If
+    // the eventual target type is the same and the pointers have the same
+    // level of indirection, this must be the issue.
+    if (lhptee->isPointerType() && rhptee->isPointerType()) {
+      do {
+        lhptee = lhptee->getAs<PointerType>()->getPointeeType();
+        rhptee = rhptee->getAs<PointerType>()->getPointeeType();
+      
+        lhptee = Context.getCanonicalType(lhptee);
+        rhptee = Context.getCanonicalType(rhptee);
+      } while (lhptee->isPointerType() && rhptee->isPointerType());
+      
+      if (lhptee.getUnqualifiedType() == rhptee.getUnqualifiedType())
+        return IncompatibleMultiPointerQualifiers;
+    }
+    
     // General pointer incompatibility takes priority over qualifiers.
     return IncompatiblePointer;
   }
@@ -6223,6 +6241,9 @@
       return false;
     DiagKind = diag::ext_typecheck_convert_discards_qualifiers;
     break;
+  case IncompatibleMultiPointerQualifiers:
+    DiagKind = diag::err_multi_pointer_qualifier_mismatch;
+    break;
   case IntToBlockPointer:
     DiagKind = diag::err_int_to_block_pointer;
     break;