From: Douglas Gregor Date: Wed, 18 Feb 2009 21:56:37 +0000 (+0000) Subject: Downgrade complaints about calling unavailable functions to a warning X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=48f3bb9f780f6e64ab71ba0202ca04b07473805a;p=clang 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/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 18a56cf892..200ada2243 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -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 { diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index a283b73ab7..1f67e09a9c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -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") diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4358051cc5..39d049bd29 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 661124c579..a276f3c1ce 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -64,15 +64,15 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, if (IIDecl) { if (TypeDecl *TD = dyn_cast(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(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(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 9d2e06df85..8dd409bd21 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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; } } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index dee352b79b..b890637767 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b2df86abe6..dd490ec51f 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()) { - // 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()) + // See if this is a deleted function. + if (FunctionDecl *FD = dyn_cast(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()) { 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(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(VD)) && DiagnoseUseOfDecl(VD, Loc)) + return ExprError(); + if (VarDecl *Var = dyn_cast(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(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()) { - Diag(Fn->getSourceRange().getBegin(), diag::err_call_deleted_function) - << FDecl->getAttr() << FDecl->getDeclName() - << Fn->getSourceRange(); - Diag(FDecl->getLocation(), diag::note_deleted_function_here) - << FDecl->getAttr(); - 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 diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d5d2b08130..ea59b644c9 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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; diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index cbcfa056a2..25b41c64de 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -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(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index ffb29795f5..f2c7de2fae 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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())) + 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()) { + // 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. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8b7d8fddc0..a47634ba69 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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()) { diff --git a/test/Sema/overloadable.c b/test/Sema/overloadable.c index 22ced49b61..2072292966 100644 --- a/test/Sema/overloadable.c +++ b/test/Sema/overloadable.c @@ -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'}} } diff --git a/test/SemaCXX/attr-unavailable.cpp b/test/SemaCXX/attr-unavailable.cpp index 140008a4cb..78e348ae1f 100644 --- a/test/SemaCXX/attr-unavailable.cpp +++ b/test/SemaCXX/attr-unavailable.cpp @@ -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}} } diff --git a/test/SemaObjC/protocol-atttribute-1.m b/test/SemaObjC/protocol-atttribute-1.m index 658c72c69f..21912dafae 100644 --- a/test/SemaObjC/protocol-atttribute-1.m +++ b/test/SemaObjC/protocol-atttribute-1.m @@ -1,7 +1,7 @@ // RUN: clang -fsyntax-only -verify %s __attribute ((unavailable)) -@protocol FwProto; +@protocol FwProto; // expected-note{{marked unavailable}} Class cFw = 0; // expected-warning {{'FwProto' is unavailable}} @@ -33,12 +33,12 @@ __attribute ((deprecated)) @protocol MyProto1 Class clsP1 = 0; // expected-warning {{'MyProto1' is deprecated}} -@protocol FwProto @end +@protocol FwProto @end // expected-note{{marked unavailable}} @interface MyClass2 // expected-warning {{'FwProto' is unavailable}} @end -__attribute ((unavailable)) __attribute ((deprecated)) @protocol XProto; +__attribute ((unavailable)) __attribute ((deprecated)) @protocol XProto; // expected-note{{marked unavailable}} id idX = 0; // expected-warning {{'XProto' is unavailable}} expected-warning {{'XProto' is deprecated}}