diff options
| author | George Burgess IV <george.burgess.iv@gmail.com> | 2015-12-02 21:58:08 +0000 |
|---|---|---|
| committer | George Burgess IV <george.burgess.iv@gmail.com> | 2015-12-02 21:58:08 +0000 |
| commit | 3e3bb95b6951c313dd5dd1c099184c309a3952e2 (patch) | |
| tree | 601f182e5509276b9319182864eac0e27a888b68 /clang/lib/Sema | |
| parent | ba904d4ecf66528be5dadd60665d5a979ce6b1a4 (diff) | |
| download | bcm5719-llvm-3e3bb95b6951c313dd5dd1c099184c309a3952e2.tar.gz bcm5719-llvm-3e3bb95b6951c313dd5dd1c099184c309a3952e2.zip | |
Add the `pass_object_size` attribute to clang.
`pass_object_size` is our way of enabling `__builtin_object_size` to
produce high quality results without requiring inlining to happen
everywhere.
A link to the design doc for this attribute is available at the
Differential review link below.
Differential Revision: http://reviews.llvm.org/D13263
llvm-svn: 254554
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 27 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 54 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 48 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 28 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 192 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 9 |
9 files changed, 321 insertions, 59 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e2d044c00e4..31e952cef21 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8419,6 +8419,15 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P, } } } + + // Parameters with the pass_object_size attribute only need to be marked + // constant at function definitions. Because we lack information about + // whether we're on a declaration or definition when we're instantiating the + // attribute, we need to check for constness here. + if (const auto *Attr = Param->getAttr<PassObjectSizeAttr>()) + if (!Param->getType().isConstQualified()) + Diag(Param->getLocation(), diag::err_attribute_pointers_only) + << Attr->getSpelling() << 1; } return HasInvalidParm; @@ -9869,4 +9878,3 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, << ArgumentExpr->getSourceRange() << TypeTagExpr->getSourceRange(); } - diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a6f2d5d6450..af5fdc95c90 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2621,6 +2621,21 @@ static bool checkUsingShadowRedecl(Sema &S, UsingShadowDecl *OldS, return false; } +static bool hasIdenticalPassObjectSizeAttrs(const FunctionDecl *A, + const FunctionDecl *B) { + assert(A->getNumParams() == B->getNumParams()); + + auto AttrEq = [](const ParmVarDecl *A, const ParmVarDecl *B) { + const auto *AttrA = A->getAttr<PassObjectSizeAttr>(); + const auto *AttrB = B->getAttr<PassObjectSizeAttr>(); + if (AttrA == AttrB) + return true; + return AttrA && AttrB && AttrA->getType() == AttrB->getType(); + }; + + return std::equal(A->param_begin(), A->param_end(), B->param_begin(), AttrEq); +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -2799,7 +2814,17 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Old->isInlined() && !Old->hasAttr<GNUInlineAttr>()) { UndefinedButUsed.erase(Old->getCanonicalDecl()); } - + + // If pass_object_size params don't match up perfectly, this isn't a valid + // redeclaration. + if (Old->getNumParams() > 0 && Old->getNumParams() == New->getNumParams() && + !hasIdenticalPassObjectSizeAttrs(Old, New)) { + Diag(New->getLocation(), diag::err_different_pass_object_size_params) + << New->getDeclName(); + Diag(OldLocation, PrevDiag) << Old << Old->getType(); + return true; + } + if (getLangOpts().CPlusPlus) { // (C++98 13.1p2): // Certain function declarations cannot be overloaded: diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index df1641af5f4..93e9eb15b36 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -809,6 +809,43 @@ static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handlePassObjectSizeAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (D->hasAttr<PassObjectSizeAttr>()) { + S.Diag(D->getLocStart(), diag::err_attribute_only_once_per_parameter) + << Attr.getName(); + return; + } + + Expr *E = Attr.getArgAsExpr(0); + uint32_t Type; + if (!checkUInt32Argument(S, Attr, E, Type, /*Idx=*/1)) + return; + + // pass_object_size's argument is passed in as the second argument of + // __builtin_object_size. So, it has the same constraints as that second + // argument; namely, it must be in the range [0, 3]. + if (Type > 3) { + S.Diag(E->getLocStart(), diag::err_attribute_argument_outof_range) + << Attr.getName() << 0 << 3 << E->getSourceRange(); + return; + } + + // pass_object_size is only supported on constant pointer parameters; as a + // kindness to users, we allow the parameter to be non-const for declarations. + // At this point, we have no clue if `D` belongs to a function declaration or + // definition, so we defer the constness check until later. + if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) { + S.Diag(D->getLocStart(), diag::err_attribute_pointers_only) + << Attr.getName() << 1; + return; + } + + D->addAttr(::new (S.Context) + PassObjectSizeAttr(Attr.getRange(), S.Context, (int)Type, + Attr.getAttributeSpellingListIndex())); +} + static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { ConsumableAttr::ConsumedState DefaultState; @@ -1162,10 +1199,12 @@ static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, SourceRange TypeRange, bool isReturnValue = false) { if (!S.isValidPointerAttrType(T)) { - S.Diag(Attr.getLoc(), isReturnValue - ? diag::warn_attribute_return_pointers_only - : diag::warn_attribute_pointers_only) - << Attr.getName() << AttrParmRange << TypeRange; + if (isReturnValue) + S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) + << Attr.getName() << AttrParmRange << TypeRange; + else + S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) + << Attr.getName() << AttrParmRange << TypeRange << 0; return false; } return true; @@ -2724,7 +2763,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, if (prioritynum < 101 || prioritynum > 65535) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range) - << E->getSourceRange(); + << E->getSourceRange() << Attr.getName() << 101 << 65535; Attr.setInvalid(); return; } @@ -3862,7 +3901,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx); if (!BufferTy->isPointerType()) { S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) - << Attr.getName(); + << Attr.getName() << 0; } } @@ -4972,6 +5011,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_CUDAConstant: handleSimpleAttribute<CUDAConstantAttr>(S, D, Attr); break; + case AttributeList::AT_PassObjectSize: + handlePassObjectSizeAttr(S, D, Attr); + break; case AttributeList::AT_Constructor: handleConstructorAttr(S, D, Attr); break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 6ec5fe2e2fd..67c858ece0b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -496,7 +496,7 @@ SourceRange Sema::getExprRange(Expr *E) const { //===----------------------------------------------------------------------===// /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). -ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { +ExprResult Sema::DefaultFunctionArrayConversion(Expr *E, bool Diagnose) { // Handle any placeholder expressions which made it here. if (E->getType()->isPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); @@ -511,9 +511,16 @@ ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { // If we are here, we are not calling a function but taking // its address (which is not allowed in OpenCL v1.0 s6.8.a.3). if (getLangOpts().OpenCL) { - Diag(E->getExprLoc(), diag::err_opencl_taking_function_address); + if (Diagnose) + Diag(E->getExprLoc(), diag::err_opencl_taking_function_address); return ExprError(); } + + if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) + if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) + if (!checkAddressOfFunctionIsAvailable(FD, Diagnose, E->getExprLoc())) + return ExprError(); + E = ImpCastExprToType(E, Context.getPointerType(Ty), CK_FunctionToPointerDecay).get(); } else if (Ty->isArrayType()) { @@ -706,8 +713,8 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { return Res; } -ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) { - ExprResult Res = DefaultFunctionArrayConversion(E); +ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose) { + ExprResult Res = DefaultFunctionArrayConversion(E, Diagnose); if (Res.isInvalid()) return ExprError(); Res = DefaultLvalueConversion(Res.get()); @@ -7338,7 +7345,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, // Suppress this for references: C++ 8.5.3p5. if (!LHSType->isReferenceType()) { // FIXME: We potentially allocate here even if ConvertRHS is false. - RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); + RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose); if (RHS.isInvalid()) return Incompatible; } @@ -9882,6 +9889,12 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { // expressions here, but the result of one is always an lvalue anyway. } ValueDecl *dcl = getPrimaryDecl(op); + + if (auto *FD = dyn_cast_or_null<FunctionDecl>(dcl)) + if (!checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, + op->getLocStart())) + return QualType(); + Expr::LValueClassification lval = op->ClassifyLValue(Context); unsigned AddressOfError = AO_No_Error; @@ -11831,6 +11844,25 @@ Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp) { return true; } +static bool maybeDiagnoseAssignmentToFunction(Sema &S, QualType DstType, + const Expr *SrcExpr) { + if (!DstType->isFunctionPointerType() || + !SrcExpr->getType()->isFunctionType()) + return false; + + auto *DRE = dyn_cast<DeclRefExpr>(SrcExpr->IgnoreParenImpCasts()); + if (!DRE) + return false; + + auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()); + if (!FD) + return false; + + return !S.checkAddressOfFunctionIsAvailable(FD, + /*Complain=*/true, + SrcExpr->getLocStart()); +} + bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, @@ -11963,6 +11995,12 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, DiagKind = diag::err_arc_weak_unavailable_assign; break; case Incompatible: + if (maybeDiagnoseAssignmentToFunction(*this, DstType, SrcExpr)) { + if (Complained) + *Complained = true; + return true; + } + DiagKind = diag::err_typecheck_convert_incompatible; ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 461b3b648dc..89d253981c5 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3011,6 +3011,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_VariableLengthArrayHasInitializer: case FK_PlaceholderType: case FK_ExplicitConstructor: + case FK_AddressOfUnaddressableFunction: return false; case FK_ReferenceInitOverloadFailed: @@ -4801,6 +4802,17 @@ InitializationSequence::InitializationSequence(Sema &S, InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList); } +/// Tries to get a FunctionDecl out of `E`. If it succeeds and we can take the +/// address of that function, this returns true. Otherwise, it returns false. +static bool isExprAnUnaddressableFunction(Sema &S, const Expr *E) { + auto *DRE = dyn_cast<DeclRefExpr>(E); + if (!DRE || !isa<FunctionDecl>(DRE->getDecl())) + return false; + + return !S.checkAddressOfFunctionIsAvailable( + cast<FunctionDecl>(DRE->getDecl())); +} + void InitializationSequence::InitializeFrom(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4982,7 +4994,7 @@ void InitializationSequence::InitializeFrom(Sema &S, } assert(S.getLangOpts().CPlusPlus); - + // - If the destination type is a (possibly cv-qualified) class type: if (DestType->isRecordType()) { // - If the initialization is direct-initialization, or if it is @@ -5079,6 +5091,9 @@ void InitializationSequence::InitializeFrom(Sema &S, !S.ResolveAddressOfOverloadedFunction(Initializer, DestType, false, dap)) SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); + else if (Initializer->getType()->isFunctionType() && + isExprAnUnaddressableFunction(S, Initializer)) + SetFailed(InitializationSequence::FK_AddressOfUnaddressableFunction); else SetFailed(InitializationSequence::FK_ConversionFailed); } else { @@ -6926,6 +6941,13 @@ bool InitializationSequence::Diagnose(Sema &S, break; } + case FK_AddressOfUnaddressableFunction: { + auto *FD = cast<FunctionDecl>(cast<DeclRefExpr>(Args[0])->getDecl()); + S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, + Args[0]->getLocStart()); + break; + } + case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: switch (FailedOverloadResult) { @@ -7248,6 +7270,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "array requires initializer list"; break; + case FK_AddressOfUnaddressableFunction: + OS << "address of unaddressable function was taken"; + break; + case FK_ArrayNeedsInitListOrStringLiteral: OS << "array requires initializer list or string literal"; break; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 80d497f4e50..3b81df4ef63 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1141,6 +1141,12 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, CXXRecordDecl *Class, CXXMethodDecl *CallOperator) { + // This conversion is explicitly disabled if the lambda's function has + // pass_object_size attributes on any of its parameters. + if (std::any_of(CallOperator->param_begin(), CallOperator->param_end(), + std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>))) + return; + // Add the conversion to function pointer. const FunctionProtoType *CallOpProto = CallOperator->getType()->getAs<FunctionProtoType>(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 4ac5a502819..645dbed21ba 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -38,6 +38,11 @@ using namespace clang; using namespace sema; +static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) { + return std::any_of(FD->param_begin(), FD->param_end(), + std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)); +} + /// A convenience routine for creating a decayed reference to a function. static ExprResult CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, @@ -60,12 +65,8 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, DRE->setHadMultipleCandidates(true); S.MarkDeclRefReferenced(DRE); - - ExprResult E = DRE; - E = S.DefaultFunctionArrayConversion(E.get()); - if (E.isInvalid()) - return ExprError(); - return E; + return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()), + CK_FunctionToPointerDecay); } static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, @@ -1062,6 +1063,14 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return true; } + // Though pass_object_size is placed on parameters and takes an argument, we + // consider it to be a function-level modifier for the sake of function + // identity. Either the function has one or more parameters with + // pass_object_size or it doesn't. + if (functionHasPassObjectSizeParams(New) != + functionHasPassObjectSizeParams(Old)) + return true; + // enable_if attributes are an order-sensitive part of the signature. for (specific_attr_iterator<EnableIfAttr> NewI = New->specific_attr_begin<EnableIfAttr>(), @@ -1548,6 +1557,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // Function-to-pointer conversion (C++ 4.3). SCS.First = ICK_Function_To_Pointer; + if (auto *DRE = dyn_cast<DeclRefExpr>(From->IgnoreParenCasts())) + if (auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) + if (!S.checkAddressOfFunctionIsAvailable(FD)) + return false; + // An lvalue of function type T can be converted to an rvalue of // type "pointer to T." The result is a pointer to the // function. (C++ 4.3p1). @@ -2508,10 +2522,21 @@ enum { ft_parameter_arity, ft_parameter_mismatch, ft_return_type, - ft_qualifer_mismatch, - ft_addr_enable_if + ft_qualifer_mismatch }; +/// Attempts to get the FunctionProtoType from a Type. Handles +/// MemberFunctionPointers properly. +static const FunctionProtoType *tryGetFunctionProtoType(QualType FromType) { + if (auto *FPT = FromType->getAs<FunctionProtoType>()) + return FPT; + + if (auto *MPT = FromType->getAs<MemberPointerType>()) + return MPT->getPointeeType()->getAs<FunctionProtoType>(); + + return nullptr; +} + /// HandleFunctionTypeMismatch - Gives diagnostic information for differeing /// function types. Catches different number of parameter, mismatch in /// parameter types, and different return types. @@ -2558,8 +2583,8 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, return; } - const FunctionProtoType *FromFunction = FromType->getAs<FunctionProtoType>(), - *ToFunction = ToType->getAs<FunctionProtoType>(); + const FunctionProtoType *FromFunction = tryGetFunctionProtoType(FromType), + *ToFunction = tryGetFunctionProtoType(ToType); // Both types need to be function types. if (!FromFunction || !ToFunction) { @@ -8572,7 +8597,11 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, S.IdentifyCUDAPreference(Caller, Cand2.Function); } - return false; + bool HasPS1 = Cand1.Function != nullptr && + functionHasPassObjectSizeParams(Cand1.Function); + bool HasPS2 = Cand2.Function != nullptr && + functionHasPassObjectSizeParams(Cand2.Function); + return HasPS1 != HasPS2 && HasPS1; } /// Determine whether two declarations are "equivalent" for the purposes of @@ -8642,9 +8671,6 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations( } } -static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, - unsigned NumArgs); - /// \brief Computes the best viable function (C++ 13.3.3) /// within an overload candidate set. /// @@ -8794,17 +8820,75 @@ static bool isFunctionAlwaysEnabled(const ASTContext &Ctx, return true; } +/// \brief Returns true if we can take the address of the function. +/// +/// \param Complain - If true, we'll emit a diagnostic +/// \param InOverloadResolution - For the purposes of emitting a diagnostic, are +/// we in overload resolution? +/// \param Loc - The location of the statement we're complaining about. Ignored +/// if we're not complaining, or if we're in overload resolution. +static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD, + bool Complain, + bool InOverloadResolution, + SourceLocation Loc) { + if (!isFunctionAlwaysEnabled(S.Context, FD)) { + if (Complain) { + // FIXME(gbiv): Both diagnostics below lack tests. We should add tests. + if (InOverloadResolution) + S.Diag(FD->getLocStart(), + diag::note_addrof_ovl_candidate_disabled_by_enable_if_attr); + else + S.Diag(Loc, diag::err_addrof_function_disabled_by_enable_if_attr) << FD; + } + return false; + } + + auto I = std::find_if(FD->param_begin(), FD->param_end(), + std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)); + if (I == FD->param_end()) + return true; + + if (Complain) { + // Add one to ParamNo because it's user-facing + unsigned ParamNo = std::distance(FD->param_begin(), I) + 1; + if (InOverloadResolution) + S.Diag(FD->getLocation(), + diag::note_ovl_candidate_has_pass_object_size_params) + << ParamNo; + else + S.Diag(Loc, diag::err_address_of_function_with_pass_object_size_params) + << FD << ParamNo; + } + return false; +} + +static bool checkAddressOfCandidateIsAvailable(Sema &S, + const FunctionDecl *FD) { + return checkAddressOfFunctionIsAvailable(S, FD, /*Complain=*/true, + /*InOverloadResolution=*/true, + /*Loc=*/SourceLocation()); +} + +bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, + bool Complain, + SourceLocation Loc) { + return ::checkAddressOfFunctionIsAvailable(*this, Function, Complain, + /*InOverloadResolution=*/false, + Loc); +} + // Notes the location of an overload candidate. void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType, bool TakingAddress) { + if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn)) + return; + std::string FnDesc; OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc); PartialDiagnostic PD = PDiag(diag::note_ovl_candidate) << (unsigned) K << FnDesc; - if (TakingAddress && !isFunctionAlwaysEnabled(Context, Fn)) - PD << ft_addr_enable_if; - else - HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); + + HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); Diag(Fn->getLocation(), PD); MaybeEmitInheritedConstructorNote(*this, Fn); } @@ -8858,7 +8942,7 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion( } static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, - unsigned I) { + unsigned I, bool TakingCandidateAddress) { const ImplicitConversionSequence &Conv = Cand->Conversions[I]; assert(Conv.isBad()); assert(Cand->Function && "for now, candidate must be a function"); @@ -9056,7 +9140,11 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, return; } } - + + if (TakingCandidateAddress && + !checkAddressOfCandidateIsAvailable(S, Cand->Function)) + return; + // Emit the generic diagnostic and, optionally, add the hints to it. PartialDiagnostic FDiag = S.PDiag(diag::note_ovl_candidate_bad_conv); FDiag << (unsigned) FnKind << FnDesc @@ -9167,7 +9255,8 @@ static TemplateDecl *getDescribedTemplate(Decl *Templated) { /// Diagnose a failed template-argument deduction. static void DiagnoseBadDeduction(Sema &S, Decl *Templated, DeductionFailureInfo &DeductionFailure, - unsigned NumArgs) { + unsigned NumArgs, + bool TakingCandidateAddress) { TemplateParameter Param = DeductionFailure.getTemplateParameter(); NamedDecl *ParamD; (ParamD = Param.dyn_cast<TemplateTypeParmDecl*>()) || @@ -9335,6 +9424,11 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated, } } } + + if (TakingCandidateAddress && isa<FunctionDecl>(Templated) && + !checkAddressOfCandidateIsAvailable(S, cast<FunctionDecl>(Templated))) + return; + // FIXME: For generic lambda parameters, check if the function is a lambda // call operator, and if so, emit a prettier and more informative // diagnostic that mentions 'auto' and lambda in addition to @@ -9355,14 +9449,15 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated, /// Diagnose a failed template-argument deduction, for function calls. static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, - unsigned NumArgs) { + unsigned NumArgs, + bool TakingCandidateAddress) { unsigned TDK = Cand->DeductionFailure.Result; if (TDK == Sema::TDK_TooFewArguments || TDK == Sema::TDK_TooManyArguments) { if (CheckArityMismatch(S, Cand, NumArgs)) return; } DiagnoseBadDeduction(S, Cand->Function, // pattern - Cand->DeductionFailure, NumArgs); + Cand->DeductionFailure, NumArgs, TakingCandidateAddress); } /// CUDA: diagnose an invalid call across targets. @@ -9443,7 +9538,8 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) { /// more richly for those diagnostic clients that cared, but we'd /// still have to be just as careful with the default diagnostics. static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, - unsigned NumArgs) { + unsigned NumArgs, + bool TakingCandidateAddress) { FunctionDecl *Fn = Cand->Function; // Note deleted candidates, but only if they're viable. @@ -9471,7 +9567,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, return DiagnoseArityMismatch(S, Cand, NumArgs); case ovl_fail_bad_deduction: - return DiagnoseBadDeduction(S, Cand, NumArgs); + return DiagnoseBadDeduction(S, Cand, NumArgs, TakingCandidateAddress); case ovl_fail_illegal_constructor: { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor) @@ -9489,7 +9585,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); for (unsigned N = Cand->NumConversions; I != N; ++I) if (Cand->Conversions[I].isBad()) - return DiagnoseBadConversion(S, Cand, I); + return DiagnoseBadConversion(S, Cand, I, TakingCandidateAddress); // FIXME: this currently happens when we're called from SemaInit // when user-conversion overload fails. Figure out how to handle @@ -9860,7 +9956,8 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, ++CandsShown; if (Cand->Function) - NoteFunctionCandidate(S, Cand, Args.size()); + NoteFunctionCandidate(S, Cand, Args.size(), + /*TakingCandidateAddress=*/false); else if (Cand->IsSurrogate) NoteSurrogateCandidate(S, Cand); else { @@ -9928,9 +10025,10 @@ struct CompareTemplateSpecCandidatesForDisplay { /// Diagnose a template argument deduction failure. /// We are treating these failures as overload failures due to bad /// deductions. -void TemplateSpecCandidate::NoteDeductionFailure(Sema &S) { +void TemplateSpecCandidate::NoteDeductionFailure(Sema &S, + bool ForTakingAddress) { DiagnoseBadDeduction(S, Specialization, // pattern - DeductionFailure, /*NumArgs=*/0); + DeductionFailure, /*NumArgs=*/0, ForTakingAddress); } void TemplateSpecCandidateSet::destroyCandidates() { @@ -9983,7 +10081,7 @@ void TemplateSpecCandidateSet::NoteCandidates(Sema &S, SourceLocation Loc) { assert(Cand->Specialization && "Non-matching built-in candidates are not added to Cands."); - Cand->NoteDeductionFailure(S); + Cand->NoteDeductionFailure(S, ForTakingAddress); } if (I != E) @@ -10048,7 +10146,7 @@ public: HasComplained(false), OvlExprInfo(OverloadExpr::find(SourceExpr)), OvlExpr(OvlExprInfo.Expression), - FailedCandidates(OvlExpr->getNameLoc()) { + FailedCandidates(OvlExpr->getNameLoc(), /*ForTakingAddress=*/true) { ExtractUnqualifiedFunctionTypeFromTargetType(); if (TargetFunctionType->isFunctionType()) { @@ -10182,10 +10280,9 @@ private: Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl()); assert(S.isSameOrCompatibleFunctionType( Context.getCanonicalType(Specialization->getType()), - Context.getCanonicalType(TargetFunctionType)) || - (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType())); + Context.getCanonicalType(TargetFunctionType))); - if (!isFunctionAlwaysEnabled(S.Context, Specialization)) + if (!S.checkAddressOfFunctionIsAvailable(Specialization)) return false; Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); @@ -10218,7 +10315,7 @@ private: return false; } - if (!isFunctionAlwaysEnabled(S.Context, FunDecl)) + if (!S.checkAddressOfFunctionIsAvailable(FunDecl)) return false; QualType ResultTy; @@ -10341,8 +10438,9 @@ public: I != IEnd; ++I) if (FunctionDecl *Fun = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl())) - S.NoteOverloadCandidate(Fun, TargetFunctionType, - /*TakingAddress=*/true); + if (!functionHasPassObjectSizeParams(Fun)) + S.NoteOverloadCandidate(Fun, TargetFunctionType, + /*TakingAddress=*/true); FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart()); } } @@ -11052,9 +11150,23 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, if (!Recovery.isInvalid()) return Recovery; - SemaRef.Diag(Fn->getLocStart(), - diag::err_ovl_no_viable_function_in_call) - << ULE->getName() << Fn->getSourceRange(); + // If the user passes in a function that we can't take the address of, we + // generally end up emitting really bad error messages. Here, we attempt to + // emit better ones. + for (const Expr *Arg : Args) { + if (!Arg->getType()->isFunctionType()) + continue; + if (auto *DRE = dyn_cast<DeclRefExpr>(Arg->IgnoreParenImpCasts())) { + auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()); + if (FD && + !SemaRef.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true, + Arg->getExprLoc())) + return ExprError(); + } + } + + SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_no_viable_function_in_call) + << ULE->getName() << Fn->getSourceRange(); CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, Args); break; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 2b637029640..bd868139df2 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2748,7 +2748,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, typedef PartialSpecMatchResult MatchResult; SmallVector<MatchResult, 4> Matched; SourceLocation PointOfInstantiation = TemplateNameLoc; - TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); + TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation, + /*ForTakingAddress=*/false); // 1. Attempt to find the closest partial specialization that this // specializes, if any. @@ -6822,7 +6823,8 @@ bool Sema::CheckFunctionTemplateSpecialization( // The set of function template specializations that could match this // explicit function template specialization. UnresolvedSet<8> Candidates; - TemplateSpecCandidateSet FailedCandidates(FD->getLocation()); + TemplateSpecCandidateSet FailedCandidates(FD->getLocation(), + /*ForTakingAddress=*/false); llvm::SmallDenseMap<FunctionDecl *, TemplateArgumentListInfo, 8> ConvertedTemplateArgs; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index e7d10d707bb..7faa3b3f178 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5483,9 +5483,12 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, // Pointer type qualifiers can only operate on pointer types, but not // pointer-to-member types. if (!isa<PointerType>(Desugared)) { - S.Diag(Attr.getLoc(), Type->isMemberPointerType() ? - diag::err_attribute_no_member_pointers : - diag::err_attribute_pointers_only) << Attr.getName(); + if (Type->isMemberPointerType()) + S.Diag(Attr.getLoc(), diag::err_attribute_no_member_pointers) + << Attr.getName(); + else + S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) + << Attr.getName() << 0; return true; } |

