diff options
author | George Burgess IV <george.burgess.iv@gmail.com> | 2015-10-12 19:57:04 +0000 |
---|---|---|
committer | George Burgess IV <george.burgess.iv@gmail.com> | 2015-10-12 19:57:04 +0000 |
commit | 5f21c718007fdc3b801690ef96908b43b8a1924e (patch) | |
tree | ec62116b246a319fd019f1f1545b620ec919cf3e /clang/lib/Sema/SemaOverload.cpp | |
parent | 3320bcd81569bcf9dc73b02bfc6b08352ab4cf22 (diff) | |
download | bcm5719-llvm-5f21c718007fdc3b801690ef96908b43b8a1924e.tar.gz bcm5719-llvm-5f21c718007fdc3b801690ef96908b43b8a1924e.zip |
[Sema] Make `&function_with_enable_if_attrs` an error
This fixes a bug where one can take the address of a conditionally
enabled function to drop its enable_if guards. For example:
int foo(int a) __attribute__((enable_if(a > 0, "")));
int (*p)(int) = &foo;
int result = p(-1); // compilation succeeds; calls foo(-1)
Overloading logic has been updated to reflect this change, as well.
Functions with enable_if attributes that are always true are still
allowed to have their address taken.
Differential Revision: http://reviews.llvm.org/D13607
llvm-svn: 250090
Diffstat (limited to 'clang/lib/Sema/SemaOverload.cpp')
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 57 |
1 files changed, 44 insertions, 13 deletions
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index b646c853561..44cb166f25b 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2508,7 +2508,8 @@ enum { ft_parameter_arity, ft_parameter_mismatch, ft_return_type, - ft_qualifer_mismatch + ft_qualifer_mismatch, + ft_addr_enable_if }; /// HandleFunctionTypeMismatch - Gives diagnostic information for differeing @@ -8683,20 +8684,37 @@ void MaybeEmitInheritedConstructorNote(Sema &S, Decl *Fn) { } // end anonymous namespace +static bool isFunctionAlwaysEnabled(const ASTContext &Ctx, + const FunctionDecl *FD) { + for (auto *EnableIf : FD->specific_attrs<EnableIfAttr>()) { + bool AlwaysTrue; + if (!EnableIf->getCond()->EvaluateAsBooleanCondition(AlwaysTrue, Ctx)) + return false; + if (!AlwaysTrue) + return false; + } + return true; +} + // Notes the location of an overload candidate. -void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType) { +void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType, + bool TakingAddress) { std::string FnDesc; OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc); PartialDiagnostic PD = PDiag(diag::note_ovl_candidate) << (unsigned) K << FnDesc; - HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); + if (TakingAddress && !isFunctionAlwaysEnabled(Context, Fn)) + PD << ft_addr_enable_if; + else + HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); Diag(Fn->getLocation(), PD); MaybeEmitInheritedConstructorNote(*this, Fn); } // Notes the location of all overload candidates designated through // OverloadedExpr -void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr, QualType DestType) { +void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType, + bool TakingAddress) { assert(OverloadedExpr->getType() == Context.OverloadTy); OverloadExpr::FindResult Ovl = OverloadExpr::find(OverloadedExpr); @@ -8707,10 +8725,11 @@ void Sema::NoteAllOverloadCandidates(Expr* OverloadedExpr, QualType DestType) { I != IEnd; ++I) { if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(FunTmpl->getTemplatedDecl(), DestType); + NoteOverloadCandidate(FunTmpl->getTemplatedDecl(), DestType, + TakingAddress); } else if (FunctionDecl *Fun = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(Fun, DestType); + NoteOverloadCandidate(Fun, DestType, TakingAddress); } } } @@ -10035,7 +10054,12 @@ private: Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl()); assert(S.isSameOrCompatibleFunctionType( Context.getCanonicalType(Specialization->getType()), - Context.getCanonicalType(TargetFunctionType))); + Context.getCanonicalType(TargetFunctionType)) || + (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType())); + + if (!isFunctionAlwaysEnabled(S.Context, Specialization)) + return false; + Matches.push_back(std::make_pair(CurAccessFunPair, Specialization)); return true; } @@ -10066,13 +10090,17 @@ private: return false; } + if (!isFunctionAlwaysEnabled(S.Context, FunDecl)) + return false; + QualType ResultTy; if (Context.hasSameUnqualifiedType(TargetFunctionType, FunDecl->getType()) || S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType, - ResultTy)) { - Matches.push_back(std::make_pair(CurAccessFunPair, - cast<FunctionDecl>(FunDecl->getCanonicalDecl()))); + ResultTy) || + (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType())) { + Matches.push_back(std::make_pair( + CurAccessFunPair, cast<FunctionDecl>(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; return true; } @@ -10174,7 +10202,8 @@ public: << OvlExpr->getName() << TargetFunctionType << OvlExpr->getSourceRange(); if (FailedCandidates.empty()) - S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType); + S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType, + /*TakingAddress=*/true); else { // We have some deduction failure messages. Use them to diagnose // the function templates, and diagnose the non-template candidates @@ -10184,7 +10213,8 @@ public: I != IEnd; ++I) if (FunctionDecl *Fun = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl())) - S.NoteOverloadCandidate(Fun, TargetFunctionType); + S.NoteOverloadCandidate(Fun, TargetFunctionType, + /*TakingAddress=*/true); FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart()); } } @@ -10222,7 +10252,8 @@ public: S.Diag(OvlExpr->getLocStart(), diag::err_addr_ovl_ambiguous) << OvlExpr->getName() << OvlExpr->getSourceRange(); - S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType); + S.NoteAllOverloadCandidates(OvlExpr, TargetFunctionType, + /*TakingAddress=*/true); } bool hadMultipleCandidates() const { return (OvlExpr->getNumDecls() > 1); } |