When computing the composite pointer type for relational comparisons,
equality comparisons, and conditional operators, produce a composite
pointer type with the appropriate additional "const" qualifiers if the
pointer types would otherwise be incompatible. This is a small
extension (also present in GCC and EDG in a slightly different form)
that permits code like:

  void** i; void const** j; 
  i == j; 

with the following extwarn:

t.cpp:5:5: warning: comparison of distinct pointer types ('void **' and
      'void const **') uses non-standard composite pointer type
      'void const *const *' [-pedantic]
  i == j; 
  ~ ^  ~

Fixes PR6346, and I'll be filing a core issue about this with the C++
committee.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97177 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 2ed4bf6..42f9838 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3947,7 +3947,8 @@
     Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
   QualType CXXCheckConditionalOperands( // C++ 5.16
     Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
-  QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9
+  QualType FindCompositePointerType(Expr *&E1, Expr *&E2,
+                                    bool *NonStandardCompositeType = 0);
 
   QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS,
                                         SourceLocation questionLoc);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index b074381..fc89b15 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -5324,11 +5324,18 @@
       //
       // C++ [expr.eq]p1 uses the same notion for (in)equality
       // comparisons of pointers.
-      QualType T = FindCompositePointerType(lex, rex);
+      bool NonStandardCompositeType = false;
+      QualType T = FindCompositePointerType(lex, rex,
+                              isSFINAEContext()? 0 : &NonStandardCompositeType);
       if (T.isNull()) {
         Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
           << lType << rType << lex->getSourceRange() << rex->getSourceRange();
         return QualType();
+      } else if (NonStandardCompositeType) {
+        Diag(Loc, 
+             diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
+          << lType << rType << T 
+          << lex->getSourceRange() << rex->getSourceRange();
       }
 
       ImpCastExprToType(lex, T, CastExpr::CK_BitCast);
@@ -5390,11 +5397,18 @@
       //   of one of the operands, with a cv-qualification signature (4.4)
       //   that is the union of the cv-qualification signatures of the operand
       //   types.
-      QualType T = FindCompositePointerType(lex, rex);
+      bool NonStandardCompositeType = false;
+      QualType T = FindCompositePointerType(lex, rex,
+                              isSFINAEContext()? 0 : &NonStandardCompositeType);
       if (T.isNull()) {
         Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
-        << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+          << lType << rType << lex->getSourceRange() << rex->getSourceRange();
         return QualType();
+      } else if (NonStandardCompositeType) {
+        Diag(Loc, 
+             diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
+          << lType << rType << T 
+          << lex->getSourceRange() << rex->getSourceRange();
       }
 
       ImpCastExprToType(lex, T, CastExpr::CK_BitCast);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 1a6fdd7..df9442c 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2080,9 +2080,18 @@
   //      performed to bring them to a common type, whose cv-qualification
   //      shall match the cv-qualification of either the second or the third
   //      operand. The result is of the common type.
-  QualType Composite = FindCompositePointerType(LHS, RHS);
-  if (!Composite.isNull())
+  bool NonStandardCompositeType = false;
+  QualType Composite = FindCompositePointerType(LHS, RHS,
+                              isSFINAEContext()? 0 : &NonStandardCompositeType);
+  if (!Composite.isNull()) {
+    if (NonStandardCompositeType)
+      Diag(QuestionLoc, 
+           diag::ext_typecheck_cond_incompatible_operands_nonstandard)
+        << LTy << RTy << Composite
+        << LHS->getSourceRange() << RHS->getSourceRange();
+      
     return Composite;
+  }
   
   // Similarly, attempt to find composite type of twp objective-c pointers.
   Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc);
@@ -2101,7 +2110,16 @@
 /// and @p E2 according to C++0x 5.9p2. It converts both expressions to this
 /// type and returns it.
 /// It does not emit diagnostics.
-QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
+///
+/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find
+/// a non-standard (but still sane) composite type to which both expressions
+/// can be converted. When such a type is chosen, \c *NonStandardCompositeType
+/// will be set true.
+QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2,
+                                        bool *NonStandardCompositeType) {
+  if (NonStandardCompositeType)
+    *NonStandardCompositeType = false;
+  
   assert(getLangOptions().CPlusPlus && "This function assumes C++");
   QualType T1 = E1->getType(), T2 = E2->getType();
 
@@ -2152,12 +2170,20 @@
   ContainingClassVector MemberOfClass;
   QualType Composite1 = Context.getCanonicalType(T1),
            Composite2 = Context.getCanonicalType(T2);
+  unsigned NeedConstBefore = 0;  
   do {
     const PointerType *Ptr1, *Ptr2;
     if ((Ptr1 = Composite1->getAs<PointerType>()) &&
         (Ptr2 = Composite2->getAs<PointerType>())) {
       Composite1 = Ptr1->getPointeeType();
       Composite2 = Ptr2->getPointeeType();
+      
+      // If we're allowed to create a non-standard composite type, keep track
+      // of where we need to fill in additional 'const' qualifiers. 
+      if (NonStandardCompositeType &&
+          Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
+        NeedConstBefore = QualifierUnion.size();
+      
       QualifierUnion.push_back(
                  Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
       MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0));
@@ -2169,6 +2195,13 @@
         (MemPtr2 = Composite2->getAs<MemberPointerType>())) {
       Composite1 = MemPtr1->getPointeeType();
       Composite2 = MemPtr2->getPointeeType();
+      
+      // If we're allowed to create a non-standard composite type, keep track
+      // of where we need to fill in additional 'const' qualifiers. 
+      if (NonStandardCompositeType &&
+          Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers())
+        NeedConstBefore = QualifierUnion.size();
+      
       QualifierUnion.push_back(
                  Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
       MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
@@ -2182,6 +2215,18 @@
     break;
   } while (true);
 
+  if (NeedConstBefore && NonStandardCompositeType) {
+    // Extension: Add 'const' to qualifiers that come before the first qualifier
+    // mismatch, so that our (non-standard!) composite type meets the 
+    // requirements of C++ [conv.qual]p4 bullet 3.
+    for (unsigned I = 0; I != NeedConstBefore; ++I) {
+      if ((QualifierUnion[I] & Qualifiers::Const) == 0) {
+        QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const;
+        *NonStandardCompositeType = true;
+      }
+    }
+  }
+  
   // Rewrap the composites as pointers or member pointers with the union CVRs.
   ContainingClassVector::reverse_iterator MOC
     = MemberOfClass.rbegin();