Downgrade complaints about calling unavailable functions to a warning
(as GCC does), except when we've performed overload resolution and
found an unavailable function: in this case, we actually error.

Merge the checking of unavailable functions with the checking for
deprecated functions. This unifies a bit of code, and makes sure that
we're checking for unavailable functions in the right places. Also,
this check can cause an error. We may, eventually, want an option to
make "unavailable" warnings into errors.

Implement much of the logic needed for C++0x deleted functions, which
are effectively the same as "unavailable" functions (but always cause
an error when referenced). However, we don't have the syntax to
specify deleted functions yet :)



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64955 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 4358051..39d049b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -438,7 +438,8 @@
   enum OverloadingResult {
     OR_Success,             ///< Overload resolution succeeded.
     OR_No_Viable_Function,  ///< No viable function found.
-    OR_Ambiguous            ///< Ambiguous candidates found.
+    OR_Ambiguous,           ///< Ambiguous candidates found.
+    OR_Deleted              ///< Overload resoltuion refers to a deleted function.
   };
 
   void AddOverloadCandidate(FunctionDecl *Function, 
@@ -1022,15 +1023,8 @@
   //===--------------------------------------------------------------------===//
   // Expression Parsing Callbacks: SemaExpr.cpp.
 
-  /// DiagnoseUseOfDeprecatedDecl - If the specified decl is deprecated or
-  // unavailable, emit the corresponding diagnostics. 
-  inline void DiagnoseUseOfDeprecatedDecl(NamedDecl *D, SourceLocation Loc) {
-    if (D->hasAttrs())
-      DiagnoseUseOfDeprecatedDeclImpl(D, Loc);
-  }
-  void DiagnoseUseOfDeprecatedDeclImpl(NamedDecl *D, SourceLocation Loc);
+  bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc);
 
-  
   // Primary Expressions.
   virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                                IdentifierInfo &II,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 661124c..a276f3c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -64,15 +64,15 @@
 
   if (IIDecl) {
     if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
-      // If this typename is deprecated, emit a warning.
-      DiagnoseUseOfDeprecatedDecl(IIDecl, NameLoc);
+      // Check whether we can use this type
+      (void)DiagnoseUseOfDecl(IIDecl, NameLoc);
       
       return Context.getTypeDeclType(TD).getAsOpaquePtr();
     }
     
     if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
-      // If this typename is deprecated, emit a warning.
-      DiagnoseUseOfDeprecatedDecl(IIDecl, NameLoc);
+      // Check whether we can use this interface.
+      (void)DiagnoseUseOfDecl(IIDecl, NameLoc);
       
       return Context.getObjCInterfaceType(IDecl).getAsOpaquePtr();
     }
@@ -591,6 +591,11 @@
     if (OldQType == NewQType) {
       // We have a redeclaration.
       MergeAttributes(New, Old);
+
+      // Merge the "deleted" flag.
+      if (Old->isDeleted())
+        New->setDeleted();
+
       return MergeCXXFunctionDecl(New, Old);
     } 
 
@@ -635,6 +640,10 @@
     }
 
     MergeAttributes(New, Old);
+
+    // Merge the "deleted" flag.
+    if (Old->isDeleted())
+      New->setDeleted();
     
     return false;
   }
@@ -3125,8 +3134,8 @@
   }
 
   if (PrevDecl) {
-    // If the previous declaration was deprecated, emit a warning.
-    DiagnoseUseOfDeprecatedDecl(PrevDecl, NameLoc);
+    // Check whether the previous declaration is usable.
+    (void)DiagnoseUseOfDecl(PrevDecl, NameLoc);
     
     if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
       // If this is a use of a previous tag, or if the tag is already declared
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9d2e06d..8dd409b 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1650,6 +1650,18 @@
       Diag(Loc, diag::err_ovl_ambiguous_init) << ClassType << Range;
     PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
     return 0;
+
+  case OR_Deleted:
+    if (InitEntity)
+      Diag(Loc, diag::err_ovl_deleted_init)
+        << Best->Function->isDeleted()
+        << InitEntity << Range;
+    else
+      Diag(Loc, diag::err_ovl_deleted_init)
+        << Best->Function->isDeleted()
+        << InitEntity << Range;
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+    return 0;
   }
   
   return 0;
@@ -1736,8 +1748,12 @@
     if (Fn) {
       // Since we're performing this reference-initialization for
       // real, update the initializer with the resulting function.
-      if (!ICS)
+      if (!ICS) {
+        if (DiagnoseUseOfDecl(Fn, Init->getSourceRange().getBegin()))
+          return true;
+
         FixOverloadedFunctionReference(Init, Fn);
+      }
 
       T2 = Fn->getType();
     }
@@ -1864,7 +1880,9 @@
       return true;
       
     case OR_No_Viable_Function:
-      // There was no suitable conversion; continue with other checks.
+    case OR_Deleted:
+      // There was no suitable conversion, or we found a deleted
+      // conversion; continue with other checks.
       break;
     }
   }
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index dee352b..b890637 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -111,7 +111,7 @@
 
     // Diagnose classes that inherit from deprecated classes.
     if (SuperClassDecl)
-      DiagnoseUseOfDeprecatedDecl(SuperClassDecl, SuperLoc);
+      (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc);
     
     if (PrevDecl && SuperClassDecl == 0) {
       // The previous declaration was not a class decl. Check if we have a
@@ -270,7 +270,7 @@
       continue;
     }
     
-    DiagnoseUseOfDeprecatedDecl(PDecl, ProtocolId[i].second);
+    (void)DiagnoseUseOfDecl(PDecl, ProtocolId[i].second);
 
     // If this is a forward declaration and we are supposed to warn in this
     // case, do it.
@@ -493,7 +493,7 @@
   CDecl->setClassInterface(IDecl);
   
   // If the interface is deprecated, warn about it.
-  DiagnoseUseOfDeprecatedDecl(IDecl, ClassLoc);
+  (void)DiagnoseUseOfDecl(IDecl, ClassLoc);
 
   /// Check for duplicate interface declaration for this category
   ObjCCategoryDecl *CDeclChain;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index b2df86a..dd490ec 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -26,14 +26,23 @@
 #include "clang/Parse/Scope.h"
 using namespace clang;
 
-
-/// DiagnoseUseOfDeprecatedDeclImpl - If the specified decl is deprecated or
-// unavailable, emit the corresponding diagnostics. 
-void Sema::DiagnoseUseOfDeprecatedDeclImpl(NamedDecl *D, SourceLocation Loc) {
+/// \brief Determine whether the use of this declaration is valid, and
+/// emit any corresponding diagnostics.
+///
+/// This routine diagnoses various problems with referencing
+/// declarations that can occur when using a declaration. For example,
+/// it might warn if a deprecated or unavailable declaration is being
+/// used, or produce an error (and return true) if a C++0x deleted
+/// function is being used.
+///
+/// \returns true if there was an error (this declaration cannot be
+/// referenced), false otherwise.
+bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
   // See if the decl is deprecated.
   if (D->getAttr<DeprecatedAttr>()) {
-    // Implementing deprecated stuff requires referencing depreated stuff. Don't
-    // warn if we are implementing a deprecated construct.
+    // Implementing deprecated stuff requires referencing deprecated
+    // stuff. Don't warn if we are implementing a deprecated
+    // construct.
     bool isSilenced = false;
     
     if (NamedDecl *ND = getCurFunctionOrMethodDecl()) {
@@ -60,9 +69,22 @@
       Diag(Loc, diag::warn_deprecated) << D->getDeclName();
   }
 
-  // See if hte decl is unavailable.
-  if (D->getAttr<UnavailableAttr>())
+  // See if this is a deleted function.
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+    if (FD->isDeleted()) {
+      Diag(Loc, diag::err_deleted_function_use);
+      Diag(D->getLocation(), diag::note_unavailable_here) << true;
+      return true;
+    }
+
+  // See if the decl is unavailable
+  if (D->getAttr<UnavailableAttr>()) {
     Diag(Loc, diag::warn_unavailable) << D->getDeclName();
+    Diag(D->getLocation(), diag::note_unavailable_here) << 0;
+  }
+
+
+  return false;
 }
 
 //===----------------------------------------------------------------------===//
@@ -607,7 +629,8 @@
       ObjCInterfaceDecl *IFace = getCurMethodDecl()->getClassInterface();
       if (ObjCIvarDecl *IV = IFace->lookupInstanceVariable(II)) {
         // Check if referencing a field with __attribute__((deprecated)).
-        DiagnoseUseOfDeprecatedDecl(IV, Loc);
+        if (DiagnoseUseOfDecl(IV, Loc))
+          return ExprError();
 
         // FIXME: This should use a new expr for a direct reference, don't turn
         // this into Self->ivar, just return a BareIVarExpr or something.
@@ -628,8 +651,12 @@
     }
   }
 
-  if (getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && 
-      HasTrailingLParen && D == 0) {
+  // Determine whether this name might be a candidate for
+  // argument-dependent lookup.
+  bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) && 
+             HasTrailingLParen;
+
+  if (ADL && D == 0) {
     // We've seen something of the form
     //
     //   identifier(
@@ -791,9 +818,13 @@
                                   false, false, SS));
   ValueDecl *VD = cast<ValueDecl>(D);
 
-  // Check if referencing an identifier with __attribute__((deprecated)).
-  DiagnoseUseOfDeprecatedDecl(VD, Loc);
-  
+  // Check whether this declaration can be used. Note that we suppress
+  // this check when we're going to perform argument-dependent lookup
+  // on this function name, because this might not be the function
+  // that overload resolution actually selects.
+  if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
+    return ExprError();
+
   if (VarDecl *Var = dyn_cast<VarDecl>(VD)) {
     // Warn about constructs like:
     //   if (void *X = foo()) { ... } else { X }.
@@ -1296,6 +1327,14 @@
           << Arg->getSourceRange();
       PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
       return ExprError();
+
+    case OR_Deleted:
+      Diag(OpLoc, diag::err_ovl_deleted_oper)
+        << Best->Function->isDeleted()
+        << UnaryOperator::getOpcodeStr(Opc)
+        << Arg->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return ExprError();
     }
 
     // Either we found no viable overloaded operator or we matched a
@@ -1398,6 +1437,14 @@
           << LHSExp->getSourceRange() << RHSExp->getSourceRange();
       PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
       return ExprError();
+
+    case OR_Deleted:
+      Diag(LLoc, diag::err_ovl_deleted_oper)
+        << Best->Function->isDeleted()
+        << "[]"
+        << LHSExp->getSourceRange() << RHSExp->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return ExprError();
     }
 
     // Either we found no viable overloaded operator or we matched a
@@ -1621,8 +1668,9 @@
     if (MemberDecl->isInvalidDecl())
       return ExprError();
     
-    // Check if referencing a field with __attribute__((deprecated)).
-    DiagnoseUseOfDeprecatedDecl(MemberDecl, MemberLoc);
+    // Check the use of this field
+    if (DiagnoseUseOfDecl(MemberDecl, MemberLoc))
+      return ExprError();
 
     if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) {
       // We may have found a field within an anonymous union or struct
@@ -1681,9 +1729,10 @@
       // error cases.
       if (IV->isInvalidDecl())
         return ExprError();
-      
-      // Check if referencing a field with __attribute__((deprecated)).
-      DiagnoseUseOfDeprecatedDecl(IV, MemberLoc);
+
+      // Check whether we can reference this field.
+      if (DiagnoseUseOfDecl(IV, MemberLoc))
+        return ExprError();
       
       ObjCIvarRefExpr *MRef= new (Context) ObjCIvarRefExpr(IV, IV->getType(), 
                                                  MemberLoc, BaseExpr,
@@ -1706,8 +1755,9 @@
 
     // Search for a declared property first.
     if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(&Member)) {
-      // Check if referencing a property with __attribute__((deprecated)).
-      DiagnoseUseOfDeprecatedDecl(PD, MemberLoc);
+      // Check whether we can reference this property.
+      if (DiagnoseUseOfDecl(PD, MemberLoc))
+        return ExprError();
 
       return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
                                                      MemberLoc, BaseExpr));
@@ -1717,8 +1767,9 @@
     for (ObjCInterfaceType::qual_iterator I = IFTy->qual_begin(),
          E = IFTy->qual_end(); I != E; ++I)
       if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
-        // Check if referencing a property with __attribute__((deprecated)).
-        DiagnoseUseOfDeprecatedDecl(PD, MemberLoc);
+        // Check whether we can reference this property.
+        if (DiagnoseUseOfDecl(PD, MemberLoc))
+          return ExprError();
 
         return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
                                                        MemberLoc, BaseExpr));
@@ -1749,8 +1800,9 @@
       }
     }
     if (Getter) {
-      // Check if referencing a property with __attribute__((deprecated)).
-      DiagnoseUseOfDeprecatedDecl(Getter, MemberLoc);
+      // Check if we can reference this property.
+      if (DiagnoseUseOfDecl(Getter, MemberLoc))
+        return ExprError();
       
       // If we found a getter then this may be a valid dot-reference, we
       // will look for the matching setter, in case it is needed.
@@ -1775,10 +1827,8 @@
         }
       }
 
-      if (Setter)
-        // Check if referencing a property with __attribute__((deprecated)).
-        DiagnoseUseOfDeprecatedDecl(Setter, MemberLoc);
-
+      if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
+        return ExprError();
       
       // FIXME: we must check that the setter has property type.
       return Owned(new (Context) ObjCKVCRefExpr(Getter, Getter->getResultType(), 
@@ -1795,8 +1845,9 @@
     for (ObjCQualifiedIdType::qual_iterator I = QIdTy->qual_begin(),
          E = QIdTy->qual_end(); I != E; ++I) {
       if (ObjCPropertyDecl *PD = (*I)->FindPropertyDeclaration(&Member)) {
-        // Check if referencing a property with __attribute__((deprecated)).
-        DiagnoseUseOfDeprecatedDecl(PD, MemberLoc);
+        // Check the use of this declaration
+        if (DiagnoseUseOfDecl(PD, MemberLoc))
+          return ExprError();
         
         return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
                                                        MemberLoc, BaseExpr));
@@ -1804,8 +1855,9 @@
       // Also must look for a getter name which uses property syntax.
       Selector Sel = PP.getSelectorTable().getNullarySelector(&Member);
       if (ObjCMethodDecl *OMD = (*I)->getInstanceMethod(Sel)) {
-        // Check if referencing a property with __attribute__((deprecated)).
-        DiagnoseUseOfDeprecatedDecl(OMD, MemberLoc);
+        // Check the use of this method.
+        if (DiagnoseUseOfDecl(OMD, MemberLoc))
+          return ExprError();
         
         return Owned(new (Context) ObjCMessageExpr(BaseExpr, Sel, 
                         OMD->getResultType(), OMD, OpLoc, MemberLoc, NULL, 0));
@@ -2033,16 +2085,6 @@
                                                                Context.BoolTy,
                                                                RParenLoc));
 
-  // Check for a call to a (FIXME: deleted) or unavailable function.
-  if (FDecl && FDecl->getAttr<UnavailableAttr>()) {
-    Diag(Fn->getSourceRange().getBegin(), diag::err_call_deleted_function)
-      << FDecl->getAttr<UnavailableAttr>() << FDecl->getDeclName()
-      << Fn->getSourceRange();
-    Diag(FDecl->getLocation(), diag::note_deleted_function_here)
-      << FDecl->getAttr<UnavailableAttr>();
-    return ExprError();
-  }
-
   const FunctionType *FuncT;
   if (!Fn->getType()->isBlockPointerType()) {
     // C99 6.5.2.2p1 - "The expression that denotes the called function shall
@@ -3912,6 +3954,14 @@
           << lhs->getSourceRange() << rhs->getSourceRange();
       PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
       return ExprError();
+
+    case OR_Deleted:
+      Diag(TokLoc, diag::err_ovl_deleted_oper)
+        << Best->Function->isDeleted()
+        << BinaryOperator::getOpcodeStr(Opc)
+        << lhs->getSourceRange() << rhs->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return ExprError();
     }
 
     // Either we found no viable overloaded operator or we matched a
@@ -4012,6 +4062,14 @@
           << Input->getSourceRange();
       PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
       return ExprError();
+
+    case OR_Deleted:
+      Diag(OpLoc, diag::err_ovl_deleted_oper)
+        << Best->Function->isDeleted()
+        << UnaryOperator::getOpcodeStr(Opc)
+        << Input->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+      return ExprError();
     }
 
     // Either we found no viable overloaded operator or we matched a
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index d5d2b08..ea59b64 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -473,6 +473,13 @@
       << Name << Range;
     PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
     return true;
+
+  case OR_Deleted:
+    Diag(StartLoc, diag::err_ovl_deleted_call)
+      << Best->Function->isDeleted()
+      << Name << Range;
+    PrintOverloadCandidates(Candidates, /*OnlyViable=*/true);
+    return true;
   }
   assert(false && "Unreachable, bad result from BestViableFunction");
   return true;
@@ -775,20 +782,22 @@
     break;
 
   case ICK_Array_To_Pointer:
+    FromType = Context.getArrayDecayedType(FromType);
+    ImpCastExprToType(From, FromType);
+    break;
+
+  case ICK_Function_To_Pointer:
     if (FromType->isOverloadType()) {
       FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
       if (!Fn)
         return true;
 
+      if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
+        return true;
+
       FixOverloadedFunctionReference(From, Fn);
       FromType = From->getType();
-    } else {
-      FromType = Context.getArrayDecayedType(FromType);
     }
-    ImpCastExprToType(From, FromType);
-    break;
-
-  case ICK_Function_To_Pointer:
     FromType = Context.getPointerType(FromType);
     ImpCastExprToType(From, FromType);
     break;
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index cbcfa05..25b41c6 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -288,8 +288,8 @@
   if (!Method)
     Method = ClassDecl->lookupInstanceMethod(Sel);
 
-  if (Method)
-    DiagnoseUseOfDeprecatedDecl(Method, receiverLoc);
+  if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
+    return true;
   
   if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true, 
                                 lbrac, rbrac, returnType))
@@ -336,8 +336,8 @@
           Method = SuperDecl->lookupInstanceMethod(Sel);
     }
 
-    if (Method)
-      DiagnoseUseOfDeprecatedDecl(Method, receiverLoc);
+    if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
+      return true;
 
     if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false,
                                   lbrac, rbrac, returnType))
@@ -370,8 +370,8 @@
               ObjCImplementations[ClassDecl->getIdentifier()])
           Method = ImpDecl->getClassMethod(Sel);
       
-      if (Method)
-        DiagnoseUseOfDeprecatedDecl(Method, receiverLoc);
+      if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
+        return true;
     }
     if (!Method)
       Method = FactoryMethodPool[Sel].Method;
@@ -423,8 +423,8 @@
       Diag(lbrac, diag::warn_method_not_found_in_protocol)
         << Sel << SourceRange(lbrac, rbrac);
     
-    if (Method)
-      DiagnoseUseOfDeprecatedDecl(Method, receiverLoc);
+    if (Method && DiagnoseUseOfDecl(Method, receiverLoc))
+      return true;
   } else {
     Diag(lbrac, diag::error_bad_receiver_type)
       << RExpr->getType() << RExpr->getSourceRange();
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index ffb2979..f2c7de2 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1409,6 +1409,7 @@
       }
       
     case OR_No_Viable_Function:
+    case OR_Deleted:
       // No conversion here! We're done.
       return false;
 
@@ -3426,6 +3427,14 @@
   }
   
   // Best is the best viable function.
+  if (Best->Function &&
+      (Best->Function->isDeleted() || 
+       Best->Function->getAttr<UnavailableAttr>()))
+    return OR_Deleted;
+
+  // If Best refers to a function that is either deleted (C++0x) or
+  // unavailable (Clang extension) report an error.
+
   return OR_Success;
 }
 
@@ -3441,8 +3450,16 @@
   for (; Cand != LastCand; ++Cand) {
     if (Cand->Viable || !OnlyViable) {
       if (Cand->Function) {
-        // Normal function
-        Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
+        if (Cand->Function->isDeleted() ||
+            Cand->Function->getAttr<UnavailableAttr>()) {
+          // Deleted or "unavailable" function.
+          Diag(Cand->Function->getLocation(), diag::err_ovl_candidate_deleted)
+            << Cand->Function->isDeleted();
+        } else {
+          // Normal function
+          // FIXME: Give a better reason!
+          Diag(Cand->Function->getLocation(), diag::err_ovl_candidate);
+        }
       } else if (Cand->IsSurrogate) {
         // Desugar the type of the surrogate down to a function type,
         // retaining as many typedefs as possible while still showing
@@ -3644,6 +3661,14 @@
       << UnqualifiedName << Fn->getSourceRange();
     PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
     break;
+
+  case OR_Deleted:
+    Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call)
+      << Best->Function->isDeleted()
+      << UnqualifiedName
+      << Fn->getSourceRange();
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+    break;
   }
 
   // Overload resolution failed. Destroy all of the subexpressions and
@@ -3716,6 +3741,15 @@
       PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
       // FIXME: Leaking incoming expressions!
       return true;
+
+    case OR_Deleted:
+      Diag(MemExpr->getSourceRange().getBegin(), 
+           diag::err_ovl_deleted_member_call)
+        << Best->Function->isDeleted()
+        << Ovl->getDeclName() << MemExprE->getSourceRange();
+      PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
+      // FIXME: Leaking incoming expressions!
+      return true;
     }
 
     FixOverloadedFunctionReference(MemExpr, Method);
@@ -3831,6 +3865,14 @@
       << Object->getType() << Object->getSourceRange();
     PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
     break;
+
+  case OR_Deleted:
+    Diag(Object->getSourceRange().getBegin(),
+         diag::err_ovl_deleted_object_call)
+      << Best->Function->isDeleted()
+      << Object->getType() << Object->getSourceRange();
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+    break;
   }    
 
   if (Best == CandidateSet.end()) {
@@ -3990,6 +4032,13 @@
       << "operator->" << BasePtr->getSourceRange();
     PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
     return true;
+
+  case OR_Deleted:
+    Diag(OpLoc,  diag::err_ovl_deleted_oper)
+      << Best->Function->isDeleted()
+      << "operator->" << BasePtr->getSourceRange();
+    PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
+    return true;
   }
 
   // Convert the object parameter.
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 8b7d8fd..a47634b 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1174,6 +1174,9 @@
       ImpCastExprToType(Arg, ArgType);
     } else if (FunctionDecl *Fn 
                  = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) {
+      if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin()))
+        return true;
+
       FixOverloadedFunctionReference(Arg, Fn);
       ArgType = Arg->getType();
       if (ArgType->isFunctionType() && ParamType->isPointerType()) {