Built-in equality and relational operators have return type "bool" in C++,
not "int".

Fix a typo in the promotion of enumeration types that was causing some
integral promotions to look like integral conversions (leading to
extra ambiguities in overload resolution).

Check for "acceptable" overloaded operators based on the types of the
arguments. This is a somewhat odd check that is specified by the
standard, but I can't see why it actually matters: the overload
candidates it suppresses don't seem like they would ever be picked as
the best candidates.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59583 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 960c99a..0e62e26 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -2145,9 +2145,12 @@
           Diag(Loc, diag::warn_selfcomparison);      
   }
   
+  // The result of comparisons is 'bool' in C++, 'int' in C.
+  QualType ResultTy = getLangOptions().CPlusPlus? Context.BoolTy : Context.IntTy;
+
   if (isRelational) {
     if (lType->isRealType() && rType->isRealType())
-      return Context.IntTy;
+      return ResultTy;
   } else {
     // Check for comparisons of floating point operands using != and ==.
     if (lType->isFloatingType()) {
@@ -2156,7 +2159,7 @@
     }
     
     if (lType->isArithmeticType() && rType->isArithmeticType())
-      return Context.IntTy;
+      return ResultTy;
   }
   
   bool LHSIsNull = lex->isNullPointerConstant(Context);
@@ -2181,7 +2184,7 @@
         << lex->getSourceRange() << rex->getSourceRange();
     }
     ImpCastExprToType(rex, lType); // promote the pointer to pointer
-    return Context.IntTy;
+    return ResultTy;
   }
   // Handle block pointer types.
   if (lType->isBlockPointerType() && rType->isBlockPointerType()) {
@@ -2195,7 +2198,7 @@
         << lex->getSourceRange() << rex->getSourceRange();
     }
     ImpCastExprToType(rex, lType); // promote the pointer to pointer
-    return Context.IntTy;
+    return ResultTy;
   }
   // Allow block pointers to be compared with null pointer constants.
   if ((lType->isBlockPointerType() && rType->isPointerType()) ||
@@ -2206,7 +2209,7 @@
         << lex->getSourceRange() << rex->getSourceRange();
     }
     ImpCastExprToType(rex, lType); // promote the pointer to pointer
-    return Context.IntTy;
+    return ResultTy;
   }
 
   if ((lType->isObjCQualifiedIdType() || rType->isObjCQualifiedIdType())) {
@@ -2224,21 +2227,21 @@
           << lType.getAsString() << rType.getAsString()
           << lex->getSourceRange() << rex->getSourceRange();
         ImpCastExprToType(rex, lType);
-        return Context.IntTy;
+        return ResultTy;
       }
       ImpCastExprToType(rex, lType);
-      return Context.IntTy;
+      return ResultTy;
     }
     if (ObjCQualifiedIdTypesAreCompatible(lType, rType, true)) {
       ImpCastExprToType(rex, lType);
-      return Context.IntTy;
+      return ResultTy;
     } else {
       if ((lType->isObjCQualifiedIdType() && rType->isObjCQualifiedIdType())) {
         Diag(Loc, diag::warn_incompatible_qualified_id_operands)
           << lType.getAsString() << rType.getAsString()
           << lex->getSourceRange() << rex->getSourceRange();
         ImpCastExprToType(rex, lType);
-        return Context.IntTy;
+        return ResultTy;
       }
     }
   }
@@ -2249,7 +2252,7 @@
         << lType.getAsString() << rType.getAsString()
         << lex->getSourceRange() << rex->getSourceRange();
     ImpCastExprToType(rex, lType); // promote the integer to pointer
-    return Context.IntTy;
+    return ResultTy;
   }
   if (lType->isIntegerType() && 
       (rType->isPointerType() || rType->isObjCQualifiedIdType())) {
@@ -2258,7 +2261,7 @@
         << lType.getAsString() << rType.getAsString()
         << lex->getSourceRange() << rex->getSourceRange();
     ImpCastExprToType(lex, rType); // promote the integer to pointer
-    return Context.IntTy;
+    return ResultTy;
   }
   // Handle block pointers.
   if (lType->isBlockPointerType() && rType->isIntegerType()) {
@@ -2267,7 +2270,7 @@
         << lType.getAsString() << rType.getAsString()
         << lex->getSourceRange() << rex->getSourceRange();
     ImpCastExprToType(rex, lType); // promote the integer to pointer
-    return Context.IntTy;
+    return ResultTy;
   }
   if (lType->isIntegerType() && rType->isBlockPointerType()) {
     if (!LHSIsNull)
@@ -2275,7 +2278,7 @@
         << lType.getAsString() << rType.getAsString()
         << lex->getSourceRange() << rex->getSourceRange();
     ImpCastExprToType(lex, rType); // promote the integer to pointer
-    return Context.IntTy;
+    return ResultTy;
   }
   return InvalidOperands(Loc, lex, rex);
 }
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 749b916..98a32ef 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -637,7 +637,7 @@
       Context.IntTy, Context.UnsignedIntTy, 
       Context.LongTy, Context.UnsignedLongTy 
     };
-    for (int Idx = 0; Idx < 0; ++Idx) {
+    for (int Idx = 0; Idx < 4; ++Idx) {
       uint64_t ToSize = Context.getTypeSize(PromoteTypes[Idx]);
       if (FromSize < ToSize ||
           (FromSize == ToSize && 
@@ -1712,6 +1712,42 @@
   }
 }
 
+/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
+/// an acceptable non-member overloaded operator for a call whose
+/// arguments have types T1 (and, if non-empty, T2). This routine
+/// implements the check in C++ [over.match.oper]p3b2 concerning
+/// enumeration types.
+static bool 
+IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
+                                       QualType T1, QualType T2,
+                                       ASTContext &Context) {
+  if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
+    return true;
+
+  const FunctionTypeProto *Proto = Fn->getType()->getAsFunctionTypeProto();
+  if (Proto->getNumArgs() < 1)
+    return false;
+
+  if (T1->isEnumeralType()) {
+    QualType ArgType = Proto->getArgType(0).getNonReferenceType();
+    if (Context.getCanonicalType(T1).getUnqualifiedType()
+          == Context.getCanonicalType(ArgType).getUnqualifiedType())
+      return true;
+  }
+
+  if (Proto->getNumArgs() < 2)
+    return false;
+
+  if (!T2.isNull() && T2->isEnumeralType()) {
+    QualType ArgType = Proto->getArgType(1).getNonReferenceType();
+    if (Context.getCanonicalType(T2).getUnqualifiedType()
+          == Context.getCanonicalType(ArgType).getUnqualifiedType())
+      return true;
+  }
+
+  return false;
+}
+
 /// AddOperatorCandidates - Add the overloaded operator candidates for
 /// the operator Op that was used in an operator expression such as "x
 /// Op y". S is the scope in which the expression occurred (used for
@@ -1790,18 +1826,19 @@
       break;
     }
 
-    // FIXME: check that strange "However" condition above. It's going
-    // to need a special test.
-    if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NonMemberOps))
-      AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
-                           /*SuppressUserConversions=*/false);
-    else if (OverloadedFunctionDecl *Ovl
-               = dyn_cast_or_null<OverloadedFunctionDecl>(NonMemberOps)) {
+    if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NonMemberOps)) {
+      if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
+        AddOverloadCandidate(FD, Args, NumArgs, CandidateSet,
+                             /*SuppressUserConversions=*/false);
+    } else if (OverloadedFunctionDecl *Ovl
+                 = dyn_cast_or_null<OverloadedFunctionDecl>(NonMemberOps)) {
       for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
                                                   FEnd = Ovl->function_end();
-           F != FEnd; ++F)
-        AddOverloadCandidate(*F, Args, NumArgs, CandidateSet, 
-                             /*SuppressUserConversions=*/false);
+           F != FEnd; ++F) {
+        if (IsAcceptableNonMemberOperatorCandidate(*F, T1, T2, Context)) 
+          AddOverloadCandidate(*F, Args, NumArgs, CandidateSet, 
+                               /*SuppressUserConversions=*/false);
+      }
     }
   }
 
@@ -2476,7 +2513,8 @@
   //      the type of the entity being initialized) is a better
   //      conversion sequence than the standard conversion sequence
   //      from the return type of F2 to the destination type.
-  if (isa<CXXConversionDecl>(Cand1.Function) && 
+  if (Cand1.Function && Cand2.Function && 
+      isa<CXXConversionDecl>(Cand1.Function) && 
       isa<CXXConversionDecl>(Cand2.Function)) {
     switch (CompareStandardConversionSequences(Cand1.FinalConversion,
                                                Cand2.FinalConversion)) {