]> granicus.if.org Git - clang/commitdiff
Downgrade complaints about calling unavailable functions to a warning
authorDouglas Gregor <dgregor@apple.com>
Wed, 18 Feb 2009 21:56:37 +0000 (21:56 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 18 Feb 2009 21:56:37 +0000 (21:56 +0000)
(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

14 files changed:
include/clang/AST/Decl.h
include/clang/Basic/DiagnosticSemaKinds.def
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplate.cpp
test/Sema/overloadable.c
test/SemaCXX/attr-unavailable.cpp
test/SemaObjC/protocol-atttribute-1.m

index 18a56cf892219c90bd8617a84a6f5a147a52a7c9..200ada2243c85c0d6c7c696f3fa6bbac6474b033 100644 (file)
@@ -536,6 +536,7 @@ private:
   bool IsVirtual : 1;
   bool IsPure : 1;
   bool InheritedPrototype : 1;
+  bool IsDeleted : 1;
 
   // Move to DeclGroup when it is implemented.
   SourceLocation TypeSpecStartLoc;
@@ -548,7 +549,7 @@ protected:
       DeclContext(DK),
       ParamInfo(0), Body(0), PreviousDeclaration(0),
       SClass(S), IsInline(isInline), IsVirtual(false), IsPure(false),
-      InheritedPrototype(false), TypeSpecStartLoc(TSSL) {}
+      InheritedPrototype(false), IsDeleted(false), TypeSpecStartLoc(TSSL) {}
 
   virtual ~FunctionDecl() {}
   virtual void Destroy(ASTContext& C);
@@ -596,6 +597,27 @@ public:
   bool inheritedPrototype() { return InheritedPrototype; }
   void setInheritedPrototype() { InheritedPrototype = true; }
 
+  /// \brief Whether this function has been deleted.
+  ///
+  /// A function that is "deleted" (via the C++0x "= delete" syntax)
+  /// acts like a normal function, except that it cannot actually be
+  /// called or have its address taken. Deleted functions are
+  /// typically used in C++ overload resolution to attract arguments
+  /// whose type or lvalue/rvalue-ness would permit the use of a
+  /// different overload that would behave incorrectly. For example,
+  /// one might use deleted functions to ban implicit conversion from
+  /// a floating-point number to an Integer type:
+  ///
+  /// @code
+  /// struct Integer {
+  ///   Integer(long); // construct from a long
+  ///   Integer(double) = delete; // no construction from float or double
+  ///   Integer(long double) = delete; // no construction from long double
+  /// };
+  /// @endcode
+  bool isDeleted() const { return IsDeleted; }
+  void setDeleted() { IsDeleted = true; }
+
   /// getPreviousDeclaration - Return the previous declaration of this
   /// function.
   const FunctionDecl *getPreviousDeclaration() const {
index a283b73ab7844c3a8830bb10aa76b81e13a4a89d..1f67e09a9c478936d953cadd06433efed08abb06 100644 (file)
@@ -465,24 +465,37 @@ DIAG(err_ovl_no_viable_member_function_in_call, ERROR,
      "no matching member function for call to %0")
 DIAG(err_ovl_ambiguous_call, ERROR,
      "call to %0 is ambiguous")
+DIAG(err_ovl_deleted_call, ERROR,
+     "call to %select{unavailable|deleted}0 function %1")
 DIAG(err_ovl_ambiguous_member_call, ERROR,
      "call to member function %0 is ambiguous")
+DIAG(err_ovl_deleted_member_call, ERROR,
+     "call to %select{unavailable|deleted}0 member function %1")
 DIAG(err_ovl_candidate, NOTE,
      "candidate function")
+DIAG(err_ovl_candidate_deleted, NOTE,
+     "candidate function has been explicitly %select{made unavailable|deleted}0")
 DIAG(err_ovl_builtin_candidate, NOTE,
      "built-in candidate function %0")
 DIAG(err_ovl_no_viable_function_in_init, ERROR,
      "no matching constructor for initialization of %0")
 DIAG(err_ovl_ambiguous_init, ERROR,
      "call to constructor of %0 is ambiguous")
+DIAG(err_ovl_deleted_init, ERROR,
+     "call to %select{unavailable|deleted}0 constructor of %1")
 DIAG(err_ovl_ambiguous_oper, ERROR,
      "use of overloaded operator '%0' is ambiguous")
 DIAG(err_ovl_no_viable_oper, ERROR,
      "no viable overloaded '%0'")
+DIAG(err_ovl_deleted_oper, ERROR,
+     "overload resolution selected %select{unavailable|deleted}0 operator '%1'")
+
 DIAG(err_ovl_no_viable_object_call, ERROR,
      "no matching function for call to object of type %0")
 DIAG(err_ovl_ambiguous_object_call, ERROR,
      "call to object of type %0 is ambiguous")
+DIAG(err_ovl_deleted_object_call, ERROR,
+     "call to %select{unavailable|deleted}0 function call operator in type %1")
 DIAG(err_ovl_surrogate_cand, NOTE,
      "conversion candidate of type %0")
 DIAG(err_member_call_without_object, ERROR,
@@ -599,6 +612,8 @@ DIAG(warn_deprecated, WARNING,
      "%0 is deprecated")
 DIAG(warn_unavailable, WARNING,
      "%0 is unavailable")
+DIAG(note_unavailable_here, NOTE,
+     "function has been explicitly marked %select{unavailable|deleted}0 here")
 DIAG(err_redefinition, ERROR,
      "redefinition of %0")
 DIAG(err_static_non_static, ERROR,
@@ -1056,10 +1071,8 @@ DIAG(err_typecheck_call_too_few_args, ERROR,
      "too few arguments to %select{function|block|method}0 call")
 DIAG(err_typecheck_call_too_many_args, ERROR,
      "too many arguments to %select{function|block|method}0 call")
-DIAG(err_call_deleted_function, ERROR,
-     "call to function %1 that has been intentionally %select{deleted|made unavailable}0 ")
-DIAG(note_deleted_function_here, NOTE,
-     "%select{deleted|unavailable}0 function is declared here")
+DIAG(err_deleted_function_use, ERROR,
+     "attempt to use a deleted function")
 DIAG(warn_cannot_pass_non_pod_arg_to_vararg, WARNING,
      "cannot pass object of non-POD type %0 through variadic "
      "%select{function|block|method}1; call will abort at runtime")
index 4358051cc52764fb933d7e95c979a85147da7f0e..39d049bd29aca3ae80fd6ff45efb75941b61c5f4 100644 (file)
@@ -438,7 +438,8 @@ public:
   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 @@ public:
   //===--------------------------------------------------------------------===//
   // 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,
index 661124c579feb9a8fa5fff3805d1ab8102438709..a276f3c1cee1e9dee9b677b9adcb6e12efa1671e 100644 (file)
@@ -64,15 +64,15 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
 
   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 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
     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 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
     }
 
     MergeAttributes(New, Old);
+
+    // Merge the "deleted" flag.
+    if (Old->isDeleted())
+      New->setDeleted();
     
     return false;
   }
@@ -3125,8 +3134,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
   }
 
   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
index 9d2e06df855f0a2a1561b0f7a9947b845a683aee..8dd409bd218389a7ae38847016c31266147e5bef 100644 (file)
@@ -1650,6 +1650,18 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
       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 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
     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 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
       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;
     }
   }
index dee352b79b8e98e6c7a43d52b98021bf253bd9cf..b8906377671ab0d0fae2f2917cc50c503940bdc8 100644 (file)
@@ -111,7 +111,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
 
     // 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 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
       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 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
   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;
index b2df86abe63f70ddf05ff2531a2290b52b90d3aa..dd490ec51fc6db649cc8be1e072dc010f442eb1c 100644 (file)
 #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 @@ void Sema::DiagnoseUseOfDeprecatedDeclImpl(NamedDecl *D, SourceLocation Loc) {
       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 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
       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 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
     }
   }
 
-  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 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
                                   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 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
           << 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
           << 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 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
     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 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
       // 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 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
 
     // 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 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
     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 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
       }
     }
     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 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
         }
       }
 
-      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 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
     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 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
       // 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 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
                                                                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 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
           << 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 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
           << 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
index d5d2b08130f062f263c65c849ef6a89b49e2b091..ea59b644c90d3e3516acedd156589efd1000ed28 100644 (file)
@@ -473,6 +473,13 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
       << 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 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
     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;
index cbcfa056a29f6318e1a0985074fe2c6adfc35d13..25b41c64decce46c3d1e8b886c5d009d46214cdb 100644 (file)
@@ -288,8 +288,8 @@ Sema::ExprResult Sema::ActOnClassMessage(
   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 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
           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 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
               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 @@ Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
       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();
index ffb29795f587bc7f9d79ebff537ebbef80129150..f2c7de2faebc24961b5610fac1a23ed4748d6011 100644 (file)
@@ -1409,6 +1409,7 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
       }
       
     case OR_No_Viable_Function:
+    case OR_Deleted:
       // No conversion here! We're done.
       return false;
 
@@ -3426,6 +3427,14 @@ Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
   }
   
   // 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 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
   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 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
       << 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 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
       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 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
       << 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 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
       << "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.
index 8b7d8fddc052b2883b0582745ea6199592c28550..a47634ba694b5f30aa769605423658824140d3d8 100644 (file)
@@ -1174,6 +1174,9 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
       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()) {
index 22ced49b61a020458e1970f6be167c86af266361..20722929662354ee6e063a3b2639caaf5c3e547f 100644 (file)
@@ -43,11 +43,11 @@ long double promote(long double) __attribute__((__overloadable__));
 
 void promote() __attribute__((__overloadable__)); // expected-error{{'overloadable' function 'promote' must have a prototype}}
 void promote(...) __attribute__((__overloadable__, __unavailable__)); // \
-    // expected-note{{unavailable function is declared here}}
+    // expected-note{{candidate function}}
 
 void test_promote(short* sp) {
   promote(1.0);
-  promote(sp); // expected-error{{call to function 'promote' that has been intentionally made unavailable}}
+  promote(sp); // expected-error{{call to unavailable function 'promote'}}
 }
 
 
index 140008a4cba04133afae2b6520625d757275049f..78e348ae1f693e887cabeece957fcdf9d46e551a 100644 (file)
@@ -2,10 +2,19 @@
 
 int &foo(int);
 double &foo(double);
-void foo(...) __attribute__((__unavailable__)); // expected-note{{unavailable function is declared here}}
+void foo(...) __attribute__((__unavailable__)); // expected-note {{candidate function}} \
+// expected-note{{function has been explicitly marked unavailable here}}
+
+void bar(...) __attribute__((__unavailable__)); // expected-note 2{{explicitly marked unavailable}}
 
 void test_foo(short* sp) {
   int &ir = foo(1);
   double &dr = foo(1.0);
-  foo(sp); // expected-error{{call to function 'foo' that has been intentionally made unavailable}}
+  foo(sp); // expected-error{{call to unavailable function 'foo'}}
+
+  void (*fp)(...) = &bar; // expected-warning{{'bar' is unavailable}}
+  void (*fp2)(...) = bar; // expected-warning{{'bar' is unavailable}}
+
+  int &(*fp3)(int) = foo;
+  void (*fp4)(...) = foo; // expected-warning{{'foo' is unavailable}}
 }
index 658c72c69f17e969ee359c219f9e7e53d4434447..21912dafaeb9dc04ff49807ee5f18f0b63f342a1 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: clang -fsyntax-only -verify %s
 
 __attribute ((unavailable))
-@protocol FwProto;
+@protocol FwProto; // expected-note{{marked unavailable}}
 
 Class <FwProto> cFw = 0;  // expected-warning {{'FwProto' is unavailable}}
 
@@ -33,12 +33,12 @@ __attribute ((deprecated)) @protocol MyProto1
 
 Class <MyProto1> clsP1 = 0;  // expected-warning {{'MyProto1' is deprecated}}
 
-@protocol FwProto @end
+@protocol FwProto @end // expected-note{{marked unavailable}}
 
 @interface MyClass2 <FwProto> // expected-warning {{'FwProto' is unavailable}}
 @end
 
-__attribute ((unavailable)) __attribute ((deprecated)) @protocol XProto;
+__attribute ((unavailable)) __attribute ((deprecated)) @protocol XProto; // expected-note{{marked unavailable}}
 
 id <XProto> idX = 0; // expected-warning {{'XProto' is unavailable}} expected-warning {{'XProto' is deprecated}}