Merged in r293784, as discussed on the commit thread for r291963. Thanks, Hans
On Sun, Jan 29, 2017 at 5:59 PM, George Burgess IV <george.burgess...@gmail.com> wrote: > Hi! > > Now that the buidbots seem content, I think that this (...along with the > minor fix to the test in r293369) should be committed to the 4.0 branch. > > Richard, Hans, are you both OK with this? > > On Fri, Jan 27, 2017 at 6:19 PM, George Burgess IV via cfe-commits > <cfe-commits@lists.llvm.org> wrote: >> >> Author: gbiv >> Date: Fri Jan 27 20:19:40 2017 >> New Revision: 293360 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=293360&view=rev >> Log: >> Change how we handle diagnose_if attributes. >> >> This patch changes how we handle argument-dependent `diagnose_if` >> attributes. In particular, we now check them in the same place that we >> check for things like passing NULL to Nonnull args, etc. This is >> basically better in every way than how we were handling them before. :) >> >> This fixes PR31638, PR31639, and PR31640. >> >> Differential Revision: https://reviews.llvm.org/D28889 >> >> Modified: >> cfe/trunk/include/clang/Sema/Overload.h >> cfe/trunk/include/clang/Sema/Sema.h >> cfe/trunk/lib/Sema/SemaChecking.cpp >> cfe/trunk/lib/Sema/SemaExpr.cpp >> cfe/trunk/lib/Sema/SemaExprCXX.cpp >> cfe/trunk/lib/Sema/SemaLookup.cpp >> cfe/trunk/lib/Sema/SemaOverload.cpp >> cfe/trunk/test/Sema/diagnose_if.c >> cfe/trunk/test/SemaCXX/diagnose_if.cpp >> >> Modified: cfe/trunk/include/clang/Sema/Overload.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/include/clang/Sema/Overload.h (original) >> +++ cfe/trunk/include/clang/Sema/Overload.h Fri Jan 27 20:19:40 2017 >> @@ -675,26 +675,6 @@ namespace clang { >> /// to be used while performing partial ordering of function >> templates. >> unsigned ExplicitCallArguments; >> >> - /// The number of diagnose_if attributes that this overload >> triggered. >> - /// If any of the triggered attributes are errors, this won't count >> - /// diagnose_if warnings. >> - unsigned NumTriggeredDiagnoseIfs = 0; >> - >> - /// Basically a TinyPtrVector<DiagnoseIfAttr *> that doesn't own the >> vector: >> - /// If NumTriggeredDiagnoseIfs is 0 or 1, this is a DiagnoseIfAttr *, >> - /// otherwise it's a pointer to an array of `NumTriggeredDiagnoseIfs` >> - /// DiagnoseIfAttr *s. >> - llvm::PointerUnion<DiagnoseIfAttr *, DiagnoseIfAttr **> >> DiagnoseIfInfo; >> - >> - /// Gets an ArrayRef for the data at DiagnoseIfInfo. Note that this >> may give >> - /// you a pointer into DiagnoseIfInfo. >> - ArrayRef<DiagnoseIfAttr *> getDiagnoseIfInfo() const { >> - auto *Ptr = NumTriggeredDiagnoseIfs <= 1 >> - ? DiagnoseIfInfo.getAddrOfPtr1() >> - : DiagnoseIfInfo.get<DiagnoseIfAttr **>(); >> - return {Ptr, NumTriggeredDiagnoseIfs}; >> - } >> - >> union { >> DeductionFailureInfo DeductionFailure; >> >> @@ -759,9 +739,8 @@ namespace clang { >> SmallVector<OverloadCandidate, 16> Candidates; >> llvm::SmallPtrSet<Decl *, 16> Functions; >> >> - // Allocator for ConversionSequenceLists and DiagnoseIfAttr* arrays. >> - // We store the first few of each of these inline to avoid allocation >> for >> - // small sets. >> + // Allocator for ConversionSequenceLists. We store the first few of >> these >> + // inline to avoid allocation for small sets. >> llvm::BumpPtrAllocator SlabAllocator; >> >> SourceLocation Loc; >> @@ -776,6 +755,8 @@ namespace clang { >> /// from the slab allocator. >> /// FIXME: It would probably be nice to have a SmallBumpPtrAllocator >> /// instead. >> + /// FIXME: Now that this only allocates ImplicitConversionSequences, >> do we >> + /// want to un-generalize this? >> template <typename T> >> T *slabAllocate(unsigned N) { >> // It's simpler if this doesn't need to consider alignment. >> @@ -809,11 +790,6 @@ namespace clang { >> SourceLocation getLocation() const { return Loc; } >> CandidateSetKind getKind() const { return Kind; } >> >> - /// Make a DiagnoseIfAttr* array in a block of memory that will live >> for >> - /// as long as this OverloadCandidateSet. Returns a pointer to the >> start >> - /// of that array. >> - DiagnoseIfAttr **addDiagnoseIfComplaints(ArrayRef<DiagnoseIfAttr *> >> CA); >> - >> /// \brief Determine when this overload candidate will be new to the >> /// overload set. >> bool isNewCandidate(Decl *F) { >> >> Modified: cfe/trunk/include/clang/Sema/Sema.h >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/include/clang/Sema/Sema.h (original) >> +++ cfe/trunk/include/clang/Sema/Sema.h Fri Jan 27 20:19:40 2017 >> @@ -2545,14 +2545,14 @@ public: >> void AddMethodCandidate(DeclAccessPair FoundDecl, >> QualType ObjectType, >> Expr::Classification ObjectClassification, >> - Expr *ThisArg, ArrayRef<Expr *> Args, >> + ArrayRef<Expr *> Args, >> OverloadCandidateSet& CandidateSet, >> bool SuppressUserConversion = false); >> void AddMethodCandidate(CXXMethodDecl *Method, >> DeclAccessPair FoundDecl, >> CXXRecordDecl *ActingContext, QualType >> ObjectType, >> Expr::Classification ObjectClassification, >> - Expr *ThisArg, ArrayRef<Expr *> Args, >> + ArrayRef<Expr *> Args, >> OverloadCandidateSet& CandidateSet, >> bool SuppressUserConversions = false, >> bool PartialOverloading = false, >> @@ -2563,7 +2563,6 @@ public: >> TemplateArgumentListInfo >> *ExplicitTemplateArgs, >> QualType ObjectType, >> Expr::Classification >> ObjectClassification, >> - Expr *ThisArg, >> ArrayRef<Expr *> Args, >> OverloadCandidateSet& CandidateSet, >> bool SuppressUserConversions = false, >> @@ -2637,37 +2636,27 @@ public: >> EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> >> Args, >> bool MissingImplicitThis = false); >> >> - /// Check the diagnose_if attributes on the given function. Returns the >> - /// first succesful fatal attribute, or null if calling Function(Args) >> isn't >> - /// an error. >> - /// >> - /// This only considers ArgDependent DiagnoseIfAttrs. >> - /// >> - /// This will populate Nonfatal with all non-error DiagnoseIfAttrs that >> - /// succeed. If this function returns non-null, the contents of >> Nonfatal are >> - /// unspecified. >> - DiagnoseIfAttr * >> - checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> >> Args, >> - SmallVectorImpl<DiagnoseIfAttr *> >> &Nonfatal, >> - bool MissingImplicitThis = false, >> - Expr *ThisArg = nullptr); >> - >> - /// Check the diagnose_if expressions on the given function. Returns >> the >> - /// first succesful fatal attribute, or null if using Function isn't >> - /// an error. >> - /// >> - /// This ignores all ArgDependent DiagnoseIfAttrs. >> - /// >> - /// This will populate Nonfatal with all non-error DiagnoseIfAttrs that >> - /// succeed. If this function returns non-null, the contents of >> Nonfatal are >> - /// unspecified. >> - DiagnoseIfAttr * >> - checkArgIndependentDiagnoseIf(FunctionDecl *Function, >> - SmallVectorImpl<DiagnoseIfAttr *> >> &Nonfatal); >> - >> - /// Emits the diagnostic contained in the given DiagnoseIfAttr at Loc. >> Also >> - /// emits a note about the location of said attribute. >> - void emitDiagnoseIfDiagnostic(SourceLocation Loc, const DiagnoseIfAttr >> *DIA); >> + /// Emit diagnostics for the diagnose_if attributes on Function, >> ignoring any >> + /// non-ArgDependent DiagnoseIfAttrs. >> + /// >> + /// Argument-dependent diagnose_if attributes should be checked each >> time a >> + /// function is used as a direct callee of a function call. >> + /// >> + /// Returns true if any errors were emitted. >> + bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function, >> + const Expr *ThisArg, >> + ArrayRef<const Expr *> Args, >> + SourceLocation Loc); >> + >> + /// Emit diagnostics for the diagnose_if attributes on Function, >> ignoring any >> + /// ArgDependent DiagnoseIfAttrs. >> + /// >> + /// Argument-independent diagnose_if attributes should be checked on >> every use >> + /// of a function. >> + /// >> + /// Returns true if any errors were emitted. >> + bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl >> *Function, >> + SourceLocation Loc); >> >> /// Returns whether the given function's address can be taken or not, >> /// optionally emitting a diagnostic if the address can't be taken. >> @@ -9937,8 +9926,8 @@ private: >> SourceLocation Loc); >> >> void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, >> - ArrayRef<const Expr *> Args, bool IsMemberFunction, >> - SourceLocation Loc, SourceRange Range, >> + const Expr *ThisArg, ArrayRef<const Expr *> Args, >> + bool IsMemberFunction, SourceLocation Loc, SourceRange >> Range, >> VariadicCallType CallType); >> >> bool CheckObjCString(Expr *Arg); >> >> Modified: cfe/trunk/lib/Sema/SemaChecking.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Jan 27 20:19:40 2017 >> @@ -2426,11 +2426,12 @@ static void CheckNonNullArguments(Sema & >> } >> >> /// Handles the checks for format strings, non-POD arguments to vararg >> -/// functions, and NULL arguments passed to non-NULL parameters. >> +/// functions, NULL arguments passed to non-NULL parameters, and >> diagnose_if >> +/// attributes. >> void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, >> - ArrayRef<const Expr *> Args, bool IsMemberFunction, >> - SourceLocation Loc, SourceRange Range, >> - VariadicCallType CallType) { >> + const Expr *ThisArg, ArrayRef<const Expr *> Args, >> + bool IsMemberFunction, SourceLocation Loc, >> + SourceRange Range, VariadicCallType CallType) { >> // FIXME: We should check as much as we can in the template definition. >> if (CurContext->isDependentContext()) >> return; >> @@ -2477,6 +2478,9 @@ void Sema::checkCall(NamedDecl *FDecl, c >> CheckArgumentWithTypeTag(I, Args.data()); >> } >> } >> + >> + if (FD) >> + diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc); >> } >> >> /// CheckConstructorCall - Check a constructor call for correctness and >> safety >> @@ -2487,8 +2491,8 @@ void Sema::CheckConstructorCall(Function >> SourceLocation Loc) { >> VariadicCallType CallType = >> Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; >> - checkCall(FDecl, Proto, Args, /*IsMemberFunction=*/true, Loc, >> SourceRange(), >> - CallType); >> + checkCall(FDecl, Proto, /*ThisArg=*/nullptr, Args, >> /*IsMemberFunction=*/true, >> + Loc, SourceRange(), CallType); >> } >> >> /// CheckFunctionCall - Check a direct function call for various >> correctness >> @@ -2503,14 +2507,20 @@ bool Sema::CheckFunctionCall(FunctionDec >> TheCall->getCallee()); >> Expr** Args = TheCall->getArgs(); >> unsigned NumArgs = TheCall->getNumArgs(); >> + >> + Expr *ImplicitThis = nullptr; >> if (IsMemberOperatorCall) { >> // If this is a call to a member operator, hide the first argument >> // from checkCall. >> // FIXME: Our choice of AST representation here is less than ideal. >> + ImplicitThis = Args[0]; >> ++Args; >> --NumArgs; >> - } >> - checkCall(FDecl, Proto, llvm::makeArrayRef(Args, NumArgs), >> + } else if (IsMemberFunction) >> + ImplicitThis = >> + cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument(); >> + >> + checkCall(FDecl, Proto, ImplicitThis, llvm::makeArrayRef(Args, >> NumArgs), >> IsMemberFunction, TheCall->getRParenLoc(), >> TheCall->getCallee()->getSourceRange(), CallType); >> >> @@ -2546,8 +2556,8 @@ bool Sema::CheckObjCMethodCall(ObjCMetho >> VariadicCallType CallType = >> Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; >> >> - checkCall(Method, nullptr, Args, >> - /*IsMemberFunction=*/false, lbrac, Method->getSourceRange(), >> + checkCall(Method, nullptr, /*ThisArg=*/nullptr, Args, >> + /*IsMemberFunction=*/false, lbrac, Method->getSourceRange(), >> CallType); >> >> return false; >> @@ -2576,7 +2586,7 @@ bool Sema::CheckPointerCall(NamedDecl *N >> CallType = VariadicFunction; >> } >> >> - checkCall(NDecl, Proto, >> + checkCall(NDecl, Proto, /*ThisArg=*/nullptr, >> llvm::makeArrayRef(TheCall->getArgs(), >> TheCall->getNumArgs()), >> /*IsMemberFunction=*/false, TheCall->getRParenLoc(), >> TheCall->getCallee()->getSourceRange(), CallType); >> @@ -2589,7 +2599,7 @@ bool Sema::CheckPointerCall(NamedDecl *N >> bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType >> *Proto) { >> VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, >> Proto, >> TheCall->getCallee()); >> - checkCall(/*FDecl=*/nullptr, Proto, >> + checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr, >> llvm::makeArrayRef(TheCall->getArgs(), >> TheCall->getNumArgs()), >> /*IsMemberFunction=*/false, TheCall->getRParenLoc(), >> TheCall->getCallee()->getSourceRange(), CallType); >> >> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Jan 27 20:19:40 2017 >> @@ -342,7 +342,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl * >> } >> >> // See if this is a deleted function. >> - SmallVector<DiagnoseIfAttr *, 4> DiagnoseIfWarnings; >> if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { >> if (FD->isDeleted()) { >> auto *Ctor = dyn_cast<CXXConstructorDecl>(FD); >> @@ -365,11 +364,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl * >> if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) >> return true; >> >> - if (const DiagnoseIfAttr *A = >> - checkArgIndependentDiagnoseIf(FD, DiagnoseIfWarnings)) { >> - emitDiagnoseIfDiagnostic(Loc, A); >> + if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc)) >> return true; >> - } >> } >> >> // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions >> @@ -385,9 +381,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl * >> return true; >> } >> >> - for (const auto *W : DiagnoseIfWarnings) >> - emitDiagnoseIfDiagnostic(Loc, W); >> - >> DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, >> ObjCPropertyAccess); >> >> @@ -5190,16 +5183,6 @@ static void checkDirectCallValidity(Sema >> << Attr->getCond()->getSourceRange() << Attr->getMessage(); >> return; >> } >> - >> - SmallVector<DiagnoseIfAttr *, 4> Nonfatal; >> - if (const DiagnoseIfAttr *Attr = S.checkArgDependentDiagnoseIf( >> - Callee, ArgExprs, Nonfatal, /*MissingImplicitThis=*/true)) { >> - S.emitDiagnoseIfDiagnostic(Fn->getLocStart(), Attr); >> - return; >> - } >> - >> - for (const auto *W : Nonfatal) >> - S.emitDiagnoseIfDiagnostic(Fn->getLocStart(), W); >> } >> >> /// ActOnCallExpr - Handle a call to Fn with the specified array of >> arguments. >> >> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jan 27 20:19:40 2017 >> @@ -6772,6 +6772,11 @@ ExprResult Sema::BuildCXXMemberCallExpr( >> CXXMemberCallExpr *CE = >> new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK, >> Exp.get()->getLocEnd()); >> + >> + if (CheckFunctionCall(Method, CE, >> + Method->getType()->castAs<FunctionProtoType>())) >> + return ExprError(); >> + >> return CE; >> } >> >> >> Modified: cfe/trunk/lib/Sema/SemaLookup.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaLookup.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaLookup.cpp Fri Jan 27 20:19:40 2017 >> @@ -2961,7 +2961,6 @@ Sema::SpecialMemberOverloadResult *Sema: >> if (CXXMethodDecl *M = >> dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) { >> if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) >> AddMethodCandidate(M, Cand, RD, ThisTy, Classification, >> - /*ThisArg=*/nullptr, >> llvm::makeArrayRef(&Arg, NumArgs), OCS, true); >> else if (CtorInfo) >> AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl, >> @@ -2974,7 +2973,7 @@ Sema::SpecialMemberOverloadResult *Sema: >> if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) >> AddMethodTemplateCandidate( >> Tmpl, Cand, RD, nullptr, ThisTy, Classification, >> - /*ThisArg=*/nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, >> true); >> + llvm::makeArrayRef(&Arg, NumArgs), OCS, true); >> else if (CtorInfo) >> AddTemplateOverloadCandidate( >> CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr, >> >> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) >> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Jan 27 20:19:40 2017 >> @@ -839,20 +839,12 @@ void OverloadCandidateSet::destroyCandid >> >> void OverloadCandidateSet::clear() { >> destroyCandidates(); >> - // DiagnoseIfAttrs are just pointers, so we don't need to destroy them. >> SlabAllocator.Reset(); >> NumInlineBytesUsed = 0; >> Candidates.clear(); >> Functions.clear(); >> } >> >> -DiagnoseIfAttr ** >> -OverloadCandidateSet::addDiagnoseIfComplaints(ArrayRef<DiagnoseIfAttr *> >> CA) { >> - auto *DIA = slabAllocate<DiagnoseIfAttr *>(CA.size()); >> - std::uninitialized_copy(CA.begin(), CA.end(), DIA); >> - return DIA; >> -} >> - >> namespace { >> class UnbridgedCastsSet { >> struct Entry { >> @@ -5831,28 +5823,6 @@ static bool IsAcceptableNonMemberOperato >> return false; >> } >> >> -static void initDiagnoseIfComplaint(Sema &S, OverloadCandidateSet >> &CandidateSet, >> - OverloadCandidate &Candidate, >> - FunctionDecl *Function, >> - ArrayRef<Expr *> Args, >> - bool MissingImplicitThis = false, >> - Expr *ExplicitThis = nullptr) { >> - SmallVector<DiagnoseIfAttr *, 8> Results; >> - if (DiagnoseIfAttr *DIA = S.checkArgDependentDiagnoseIf( >> - Function, Args, Results, MissingImplicitThis, ExplicitThis)) { >> - Results.clear(); >> - Results.push_back(DIA); >> - } >> - >> - Candidate.NumTriggeredDiagnoseIfs = Results.size(); >> - if (Results.empty()) >> - Candidate.DiagnoseIfInfo = nullptr; >> - else if (Results.size() == 1) >> - Candidate.DiagnoseIfInfo = Results[0]; >> - else >> - Candidate.DiagnoseIfInfo = >> CandidateSet.addDiagnoseIfComplaints(Results); >> -} >> - >> /// AddOverloadCandidate - Adds the given function to the set of >> /// candidate functions, using the given function call arguments. If >> /// @p SuppressUserConversions, then don't allow user-defined >> @@ -5886,10 +5856,9 @@ Sema::AddOverloadCandidate(FunctionDecl >> // object argument (C++ [over.call.func]p3), and the acting context >> // is irrelevant. >> AddMethodCandidate(Method, FoundDecl, Method->getParent(), >> QualType(), >> - Expr::Classification::makeSimpleLValue(), >> - /*ThisArg=*/nullptr, Args, CandidateSet, >> - SuppressUserConversions, PartialOverloading, >> - EarlyConversions); >> + Expr::Classification::makeSimpleLValue(), Args, >> + CandidateSet, SuppressUserConversions, >> + PartialOverloading, EarlyConversions); >> return; >> } >> // We treat a constructor like a non-member function, since its >> object >> @@ -6050,8 +6019,6 @@ Sema::AddOverloadCandidate(FunctionDecl >> Candidate.FailureKind = ovl_fail_ext_disabled; >> return; >> } >> - >> - initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Function, >> Args); >> } >> >> ObjCMethodDecl * >> @@ -6260,85 +6227,73 @@ EnableIfAttr *Sema::CheckEnableIf(Functi >> return nullptr; >> } >> >> -static bool gatherDiagnoseIfAttrs(FunctionDecl *Function, bool >> ArgDependent, >> - SmallVectorImpl<DiagnoseIfAttr *> >> &Errors, >> - SmallVectorImpl<DiagnoseIfAttr *> >> &Nonfatal) { >> - for (auto *DIA : Function->specific_attrs<DiagnoseIfAttr>()) >> - if (ArgDependent == DIA->getArgDependent()) { >> - if (DIA->isError()) >> - Errors.push_back(DIA); >> - else >> - Nonfatal.push_back(DIA); >> - } >> - >> - return !Errors.empty() || !Nonfatal.empty(); >> -} >> - >> template <typename CheckFn> >> -static DiagnoseIfAttr * >> -checkDiagnoseIfAttrsWith(const SmallVectorImpl<DiagnoseIfAttr *> &Errors, >> - SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal, >> - CheckFn &&IsSuccessful) { >> +static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD, >> + bool ArgDependent, SourceLocation >> Loc, >> + CheckFn &&IsSuccessful) { >> + SmallVector<const DiagnoseIfAttr *, 8> Attrs; >> + for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) { >> + if (ArgDependent == DIA->getArgDependent()) >> + Attrs.push_back(DIA); >> + } >> + >> + // Common case: No diagnose_if attributes, so we can quit early. >> + if (Attrs.empty()) >> + return false; >> + >> + auto WarningBegin = std::stable_partition( >> + Attrs.begin(), Attrs.end(), >> + [](const DiagnoseIfAttr *DIA) { return DIA->isError(); }); >> + >> // Note that diagnose_if attributes are late-parsed, so they appear in >> the >> // correct order (unlike enable_if attributes). >> - auto ErrAttr = llvm::find_if(Errors, IsSuccessful); >> - if (ErrAttr != Errors.end()) >> - return *ErrAttr; >> - >> - llvm::erase_if(Nonfatal, [&](DiagnoseIfAttr *A) { return >> !IsSuccessful(A); }); >> - return nullptr; >> -} >> - >> -DiagnoseIfAttr * >> -Sema::checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr >> *> Args, >> - SmallVectorImpl<DiagnoseIfAttr *> >> &Nonfatal, >> - bool MissingImplicitThis, >> - Expr *ThisArg) { >> - SmallVector<DiagnoseIfAttr *, 4> Errors; >> - if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/true, Errors, >> Nonfatal)) >> - return nullptr; >> + auto ErrAttr = llvm::find_if(llvm::make_range(Attrs.begin(), >> WarningBegin), >> + IsSuccessful); >> + if (ErrAttr != WarningBegin) { >> + const DiagnoseIfAttr *DIA = *ErrAttr; >> + S.Diag(Loc, diag::err_diagnose_if_succeeded) << DIA->getMessage(); >> + S.Diag(DIA->getLocation(), diag::note_from_diagnose_if) >> + << DIA->getParent() << DIA->getCond()->getSourceRange(); >> + return true; >> + } >> >> - SFINAETrap Trap(*this); >> - SmallVector<Expr *, 16> ConvertedArgs; >> - Expr *ConvertedThis; >> - if (!convertArgsForAvailabilityChecks(*this, Function, ThisArg, Args, >> Trap, >> - MissingImplicitThis, >> ConvertedThis, >> - ConvertedArgs)) >> - return nullptr; >> + for (const auto *DIA : llvm::make_range(WarningBegin, Attrs.end())) >> + if (IsSuccessful(DIA)) { >> + S.Diag(Loc, diag::warn_diagnose_if_succeeded) << DIA->getMessage(); >> + S.Diag(DIA->getLocation(), diag::note_from_diagnose_if) >> + << DIA->getParent() << DIA->getCond()->getSourceRange(); >> + } >> >> - return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr >> *DIA) { >> - APValue Result; >> - // It's sane to use the same ConvertedArgs for any redecl of this >> function, >> - // since EvaluateWithSubstitution only cares about the position of >> each >> - // argument in the arg list, not the ParmVarDecl* it maps to. >> - if (!DIA->getCond()->EvaluateWithSubstitution( >> - Result, Context, DIA->getParent(), ConvertedArgs, >> ConvertedThis)) >> - return false; >> - return Result.isInt() && Result.getInt().getBoolValue(); >> - }); >> + return false; >> } >> >> -DiagnoseIfAttr *Sema::checkArgIndependentDiagnoseIf( >> - FunctionDecl *Function, SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal) >> { >> - SmallVector<DiagnoseIfAttr *, 4> Errors; >> - if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/false, Errors, >> - Nonfatal)) >> - return nullptr; >> - >> - return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr >> *DIA) { >> - bool Result; >> - return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) && >> - Result; >> - }); >> +bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl >> *Function, >> + const Expr *ThisArg, >> + ArrayRef<const Expr *> >> Args, >> + SourceLocation Loc) { >> + return diagnoseDiagnoseIfAttrsWith( >> + *this, Function, /*ArgDependent=*/true, Loc, >> + [&](const DiagnoseIfAttr *DIA) { >> + APValue Result; >> + // It's sane to use the same Args for any redecl of this >> function, since >> + // EvaluateWithSubstitution only cares about the position of each >> + // argument in the arg list, not the ParmVarDecl* it maps to. >> + if (!DIA->getCond()->EvaluateWithSubstitution( >> + Result, Context, DIA->getParent(), Args, ThisArg)) >> + return false; >> + return Result.isInt() && Result.getInt().getBoolValue(); >> + }); >> } >> >> -void Sema::emitDiagnoseIfDiagnostic(SourceLocation Loc, >> - const DiagnoseIfAttr *DIA) { >> - auto Code = DIA->isError() ? diag::err_diagnose_if_succeeded >> - : diag::warn_diagnose_if_succeeded; >> - Diag(Loc, Code) << DIA->getMessage(); >> - Diag(DIA->getLocation(), diag::note_from_diagnose_if) >> - << DIA->getParent() << DIA->getCond()->getSourceRange(); >> +bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl >> *Function, >> + SourceLocation Loc) { >> + return diagnoseDiagnoseIfAttrsWith( >> + *this, Function, /*ArgDependent=*/false, Loc, >> + [&](const DiagnoseIfAttr *DIA) { >> + bool Result; >> + return DIA->getCond()->EvaluateAsBooleanCondition(Result, >> Context) && >> + Result; >> + }); >> } >> >> /// \brief Add all of the function declarations in the given function set >> to >> @@ -6356,8 +6311,8 @@ void Sema::AddFunctionCandidates(const U >> AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(), >> cast<CXXMethodDecl>(FD)->getParent(), >> Args[0]->getType(), >> Args[0]->Classify(Context), >> - Args[0], Args.slice(1), CandidateSet, >> - SuppressUserConversions, PartialOverloading); >> + Args.slice(1), CandidateSet, >> SuppressUserConversions, >> + PartialOverloading); >> else >> AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet, >> SuppressUserConversions, >> PartialOverloading); >> @@ -6369,7 +6324,7 @@ void Sema::AddFunctionCandidates(const U >> FunTmpl, F.getPair(), >> cast<CXXRecordDecl>(FunTmpl->getDeclContext()), >> ExplicitTemplateArgs, Args[0]->getType(), >> - Args[0]->Classify(Context), Args[0], Args.slice(1), >> CandidateSet, >> + Args[0]->Classify(Context), Args.slice(1), CandidateSet, >> SuppressUserConversions, PartialOverloading); >> else >> AddTemplateOverloadCandidate(FunTmpl, F.getPair(), >> @@ -6385,7 +6340,6 @@ void Sema::AddFunctionCandidates(const U >> void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, >> QualType ObjectType, >> Expr::Classification ObjectClassification, >> - Expr *ThisArg, >> ArrayRef<Expr *> Args, >> OverloadCandidateSet& CandidateSet, >> bool SuppressUserConversions) { >> @@ -6399,15 +6353,13 @@ void Sema::AddMethodCandidate(DeclAccess >> assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) && >> "Expected a member function template"); >> AddMethodTemplateCandidate(TD, FoundDecl, ActingContext, >> - /*ExplicitArgs*/ nullptr, >> - ObjectType, ObjectClassification, >> - ThisArg, Args, CandidateSet, >> + /*ExplicitArgs*/ nullptr, ObjectType, >> + ObjectClassification, Args, CandidateSet, >> SuppressUserConversions); >> } else { >> AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, >> ActingContext, >> - ObjectType, ObjectClassification, >> - ThisArg, Args, >> - CandidateSet, SuppressUserConversions); >> + ObjectType, ObjectClassification, Args, >> CandidateSet, >> + SuppressUserConversions); >> } >> } >> >> @@ -6422,7 +6374,7 @@ void >> Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, >> CXXRecordDecl *ActingContext, QualType >> ObjectType, >> Expr::Classification ObjectClassification, >> - Expr *ThisArg, ArrayRef<Expr *> Args, >> + ArrayRef<Expr *> Args, >> OverloadCandidateSet &CandidateSet, >> bool SuppressUserConversions, >> bool PartialOverloading, >> @@ -6544,9 +6496,6 @@ Sema::AddMethodCandidate(CXXMethodDecl * >> Candidate.DeductionFailure.Data = FailedAttr; >> return; >> } >> - >> - initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Method, Args, >> - /*MissingImplicitThis=*/!ThisArg, ThisArg); >> } >> >> /// \brief Add a C++ member function template as a candidate to the >> candidate >> @@ -6559,7 +6508,6 @@ Sema::AddMethodTemplateCandidate(Functio >> TemplateArgumentListInfo >> *ExplicitTemplateArgs, >> QualType ObjectType, >> Expr::Classification >> ObjectClassification, >> - Expr *ThisArg, >> ArrayRef<Expr *> Args, >> OverloadCandidateSet& CandidateSet, >> bool SuppressUserConversions, >> @@ -6613,9 +6561,9 @@ Sema::AddMethodTemplateCandidate(Functio >> assert(isa<CXXMethodDecl>(Specialization) && >> "Specialization is not a member function?"); >> AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, >> - ActingContext, ObjectType, ObjectClassification, >> - /*ThisArg=*/ThisArg, Args, CandidateSet, >> - SuppressUserConversions, PartialOverloading, >> Conversions); >> + ActingContext, ObjectType, ObjectClassification, >> Args, >> + CandidateSet, SuppressUserConversions, >> PartialOverloading, >> + Conversions); >> } >> >> /// \brief Add a C++ function template specialization as a candidate >> @@ -6942,8 +6890,6 @@ Sema::AddConversionCandidate(CXXConversi >> Candidate.DeductionFailure.Data = FailedAttr; >> return; >> } >> - >> - initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, >> None, false, From); >> } >> >> /// \brief Adds a conversion function template specialization >> @@ -7096,8 +7042,6 @@ void Sema::AddSurrogateCandidate(CXXConv >> Candidate.DeductionFailure.Data = FailedAttr; >> return; >> } >> - >> - initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, >> None); >> } >> >> /// \brief Add overload candidates for overloaded operators that are >> @@ -7146,7 +7090,7 @@ void Sema::AddMemberOperatorCandidates(O >> Oper != OperEnd; >> ++Oper) >> AddMethodCandidate(Oper.getPair(), Args[0]->getType(), >> - Args[0]->Classify(Context), Args[0], >> Args.slice(1), >> + Args[0]->Classify(Context), Args.slice(1), >> CandidateSet, >> /*SuppressUserConversions=*/false); >> } >> } >> @@ -9178,17 +9122,6 @@ void Sema::diagnoseEquivalentInternalLin >> } >> } >> >> -static bool isCandidateUnavailableDueToDiagnoseIf(const OverloadCandidate >> &OC) { >> - ArrayRef<DiagnoseIfAttr *> Info = OC.getDiagnoseIfInfo(); >> - if (!Info.empty() && Info[0]->isError()) >> - return true; >> - >> - assert(llvm::all_of(Info, >> - [](const DiagnoseIfAttr *A) { return !A->isError(); >> }) && >> - "DiagnoseIf info shouldn't have mixed warnings and errors."); >> - return false; >> -} >> - >> /// \brief Computes the best viable function (C++ 13.3.3) >> /// within an overload candidate set. >> /// >> @@ -9267,19 +9200,13 @@ OverloadCandidateSet::BestViableFunction >> // Best is the best viable function. >> if (Best->Function && >> (Best->Function->isDeleted() || >> - S.isFunctionConsideredUnavailable(Best->Function) || >> - isCandidateUnavailableDueToDiagnoseIf(*Best))) >> + S.isFunctionConsideredUnavailable(Best->Function))) >> return OR_Deleted; >> >> if (!EquivalentCands.empty()) >> S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, >> EquivalentCands); >> >> - for (const auto *W : Best->getDiagnoseIfInfo()) { >> - assert(W->isWarning() && "Errors should've been caught earlier!"); >> - S.emitDiagnoseIfDiagnostic(Loc, W); >> - } >> - >> return OR_Success; >> } >> >> @@ -10162,14 +10089,6 @@ static void NoteFunctionCandidate(Sema & >> MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); >> return; >> } >> - if (isCandidateUnavailableDueToDiagnoseIf(*Cand)) { >> - auto *A = Cand->DiagnoseIfInfo.get<DiagnoseIfAttr *>(); >> - assert(A->isError() && "Non-error diagnose_if disables a >> candidate?"); >> - S.Diag(Cand->Function->getLocation(), >> - diag::note_ovl_candidate_disabled_by_function_cond_attr) >> - << A->getCond()->getSourceRange() << A->getMessage(); >> - return; >> - } >> >> // We don't really have anything else to say about viable candidates. >> S.NoteOverloadCandidate(Cand->FoundDecl, Fn); >> @@ -12113,6 +12032,10 @@ Sema::CreateOverloadedUnaryOp(SourceLoca >> if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, >> FnDecl)) >> return ExprError(); >> >> + if (CheckFunctionCall(FnDecl, TheCall, >> + >> FnDecl->getType()->castAs<FunctionProtoType>())) >> + return ExprError(); >> + >> return MaybeBindToTemporary(TheCall); >> } else { >> // We matched a built-in operator. Convert the arguments, then >> @@ -12343,16 +12266,20 @@ Sema::CreateOverloadedBinOp(SourceLocati >> return ExprError(); >> >> ArrayRef<const Expr *> ArgsArray(Args, 2); >> + const Expr *ImplicitThis = nullptr; >> // Cut off the implicit 'this'. >> - if (isa<CXXMethodDecl>(FnDecl)) >> + if (isa<CXXMethodDecl>(FnDecl)) { >> + ImplicitThis = ArgsArray[0]; >> ArgsArray = ArgsArray.slice(1); >> + } >> >> // Check for a self move. >> if (Op == OO_Equal) >> DiagnoseSelfMove(Args[0], Args[1], OpLoc); >> >> - checkCall(FnDecl, nullptr, ArgsArray, isa<CXXMethodDecl>(FnDecl), >> OpLoc, >> - TheCall->getSourceRange(), VariadicDoesNotApply); >> + checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray, >> + isa<CXXMethodDecl>(FnDecl), OpLoc, >> TheCall->getSourceRange(), >> + VariadicDoesNotApply); >> >> return MaybeBindToTemporary(TheCall); >> } else { >> @@ -12561,6 +12488,10 @@ Sema::CreateOverloadedArraySubscriptExpr >> if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, >> FnDecl)) >> return ExprError(); >> >> + if (CheckFunctionCall(Method, TheCall, >> + >> Method->getType()->castAs<FunctionProtoType>())) >> + return ExprError(); >> + >> return MaybeBindToTemporary(TheCall); >> } else { >> // We matched a built-in operator. Convert the arguments, then >> @@ -12727,16 +12658,6 @@ Sema::BuildCallToMemberFunction(Scope *S >> TemplateArgs = &TemplateArgsBuffer; >> } >> >> - // Poor-programmer's Lazy<Expr *>; isImplicitAccess requires >> stripping >> - // parens/casts, which would be nice to avoid potentially doing >> multiple >> - // times. >> - llvm::Optional<Expr *> UnresolvedBase; >> - auto GetUnresolvedBase = [&] { >> - if (!UnresolvedBase.hasValue()) >> - UnresolvedBase = >> - UnresExpr->isImplicitAccess() ? nullptr : UnresExpr->getBase(); >> - return *UnresolvedBase; >> - }; >> for (UnresolvedMemberExpr::decls_iterator I = >> UnresExpr->decls_begin(), >> E = UnresExpr->decls_end(); I != E; ++I) { >> >> @@ -12757,14 +12678,12 @@ Sema::BuildCallToMemberFunction(Scope *S >> continue; >> >> AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType, >> - ObjectClassification, >> - /*ThisArg=*/GetUnresolvedBase(), Args, >> CandidateSet, >> + ObjectClassification, Args, CandidateSet, >> /*SuppressUserConversions=*/false); >> } else { >> AddMethodTemplateCandidate( >> cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC, >> - TemplateArgs, ObjectType, ObjectClassification, >> - /*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet, >> + TemplateArgs, ObjectType, ObjectClassification, Args, >> CandidateSet, >> /*SuppressUsedConversions=*/false); >> } >> } >> @@ -12882,16 +12801,6 @@ Sema::BuildCallToMemberFunction(Scope *S >> << Attr->getCond()->getSourceRange() << Attr->getMessage(); >> return ExprError(); >> } >> - >> - SmallVector<DiagnoseIfAttr *, 4> Nonfatal; >> - if (const DiagnoseIfAttr *Attr = checkArgDependentDiagnoseIf( >> - Method, Args, Nonfatal, false, MemE->getBase())) { >> - emitDiagnoseIfDiagnostic(MemE->getMemberLoc(), Attr); >> - return ExprError(); >> - } >> - >> - for (const auto *Attr : Nonfatal) >> - emitDiagnoseIfDiagnostic(MemE->getMemberLoc(), Attr); >> } >> >> if ((isa<CXXConstructorDecl>(CurContext) || >> @@ -12970,9 +12879,8 @@ Sema::BuildCallToObjectOfClassType(Scope >> for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); >> Oper != OperEnd; ++Oper) { >> AddMethodCandidate(Oper.getPair(), Object.get()->getType(), >> - Object.get()->Classify(Context), >> - Object.get(), Args, CandidateSet, >> - /*SuppressUserConversions=*/ false); >> + Object.get()->Classify(Context), Args, >> CandidateSet, >> + /*SuppressUserConversions=*/false); >> } >> >> // C++ [over.call.object]p2: >> @@ -13247,8 +13155,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, >> for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); >> Oper != OperEnd; ++Oper) { >> AddMethodCandidate(Oper.getPair(), Base->getType(), >> Base->Classify(Context), >> - Base, None, CandidateSet, >> - /*SuppressUserConversions=*/false); >> + None, CandidateSet, >> /*SuppressUserConversions=*/false); >> } >> >> bool HadMultipleCandidates = (CandidateSet.size() > 1); >> @@ -13322,7 +13229,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, >> Base, ResultTy, VK, OpLoc, false); >> >> if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, >> Method)) >> - return ExprError(); >> + return ExprError(); >> + >> + if (CheckFunctionCall(Method, TheCall, >> + Method->getType()->castAs<FunctionProtoType>())) >> + return ExprError(); >> >> return MaybeBindToTemporary(TheCall); >> } >> >> Modified: cfe/trunk/test/Sema/diagnose_if.c >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/diagnose_if.c?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/test/Sema/diagnose_if.c (original) >> +++ cfe/trunk/test/Sema/diagnose_if.c Fri Jan 27 20:19:40 2017 >> @@ -70,14 +70,14 @@ void runVariable() { >> >> #define _overloadable __attribute__((overloadable)) >> >> -int ovl1(const char *n) _overloadable _diagnose_if(n, "oh no", "error"); >> // expected-note{{oh no}} >> -int ovl1(void *m) _overloadable; // expected-note{{candidate function}} >> +int ovl1(const char *n) _overloadable _diagnose_if(n, "oh no", "error"); >> // expected-note{{from 'diagnose_if'}} >> +int ovl1(void *m) _overloadable; >> >> int ovl2(const char *n) _overloadable _diagnose_if(n, "oh no", "error"); >> // expected-note{{candidate function}} >> int ovl2(char *m) _overloadable; // expected-note{{candidate function}} >> void overloadsYay() { >> ovl1((void *)0); >> - ovl1(""); // expected-error{{call to unavailable function}} >> + ovl1(""); // expected-error{{oh no}} >> >> ovl2((void *)0); // expected-error{{ambiguous}} >> } >> >> Modified: cfe/trunk/test/SemaCXX/diagnose_if.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/diagnose_if.cpp?rev=293360&r1=293359&r2=293360&view=diff >> >> ============================================================================== >> --- cfe/trunk/test/SemaCXX/diagnose_if.cpp (original) >> +++ cfe/trunk/test/SemaCXX/diagnose_if.cpp Fri Jan 27 20:19:40 2017 >> @@ -2,6 +2,8 @@ >> >> #define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__))) >> >> +using size_t = unsigned long; >> + >> namespace type_dependent { >> template <typename T> >> void neverok() _diagnose_if(!T(), "oh no", "error") {} // expected-note >> 4{{from 'diagnose_if'}} >> @@ -51,14 +53,14 @@ void runAll() { >> } >> >> template <typename T> >> -void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // >> expected-note {{candidate disabled: oh no}} >> +void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // >> expected-note{{from 'diagnose_if'}} >> >> template <typename T> >> -void warnIf(T a) _diagnose_if(T() != a, "oh no", "warning") {} // >> expected-note {{from 'diagnose_if'}} >> +void warnIf(T a) _diagnose_if(T() != a, "oh no", "warning") {} // >> expected-note{{from 'diagnose_if'}} >> >> void runIf() { >> errorIf(0); >> - errorIf(1); // expected-error{{call to unavailable function}} >> + errorIf(1); // expected-error{{oh no}} >> >> warnIf(0); >> warnIf(1); // expected-warning{{oh no}} >> @@ -114,14 +116,14 @@ void runAll() { >> } >> >> template <int N> >> -void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // >> expected-note {{candidate disabled: oh no}} >> +void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // >> expected-note{{from 'diagnose_if'}} >> >> template <int N> >> -void warnIf(int a) _diagnose_if(N != a, "oh no", "warning") {} // >> expected-note {{from 'diagnose_if'}} >> +void warnIf(int a) _diagnose_if(N != a, "oh no", "warning") {} // >> expected-note{{from 'diagnose_if'}} >> >> void runIf() { >> errorIf<0>(0); >> - errorIf<0>(1); // expected-error{{call to unavailable function}} >> + errorIf<0>(1); // expected-error{{oh no}} >> >> warnIf<0>(0); >> warnIf<0>(1); // expected-warning{{oh no}} >> @@ -135,8 +137,8 @@ void foo(short); >> void bar(int); >> void bar(short) _diagnose_if(1, "oh no", "error"); >> >> -void fooArg(int a) _diagnose_if(a, "oh no", "error"); // >> expected-note{{candidate disabled: oh no}} >> -void fooArg(short); // expected-note{{candidate function}} >> +void fooArg(int a) _diagnose_if(a, "oh no", "error"); // >> expected-note{{from 'diagnose_if'}} >> +void fooArg(short); >> >> void barArg(int); >> void barArg(short a) _diagnose_if(a, "oh no", "error"); >> @@ -145,7 +147,7 @@ void runAll() { >> foo(1); // expected-error{{oh no}} >> bar(1); >> >> - fooArg(1); // expected-error{{call to unavailable function}} >> + fooArg(1); // expected-error{{oh no}} >> barArg(1); >> >> auto p = foo; // expected-error{{incompatible initializer of type >> '<overloaded function type>'}} >> @@ -188,11 +190,11 @@ struct Errors { >> void foo(int i) _diagnose_if(i, "bad i", "error"); // >> expected-note{{from 'diagnose_if'}} >> void bar(int i) _diagnose_if(i != T(), "bad i", "error"); // >> expected-note{{from 'diagnose_if'}} >> >> - void fooOvl(int i) _diagnose_if(i, "int bad i", "error"); // >> expected-note 2{{int bad i}} >> - void fooOvl(short i) _diagnose_if(i, "short bad i", "error"); // >> expected-note 2{{short bad i}} >> + void fooOvl(int i) _diagnose_if(i, "int bad i", "error"); // >> expected-note{{from 'diagnose_if'}} >> + void fooOvl(short i) _diagnose_if(i, "short bad i", "error"); // >> expected-note{{from 'diagnose_if'}} >> >> - void barOvl(int i) _diagnose_if(i != T(), "int bad i", "error"); // >> expected-note 2{{int bad i}} >> - void barOvl(short i) _diagnose_if(i != T(), "short bad i", "error"); // >> expected-note 2{{short bad i}} >> + void barOvl(int i) _diagnose_if(i != T(), "int bad i", "error"); // >> expected-note{{from 'diagnose_if'}} >> + void barOvl(short i) _diagnose_if(i != T(), "short bad i", "error"); // >> expected-note{{from 'diagnose_if'}} >> }; >> >> void runErrors() { >> @@ -203,14 +205,14 @@ void runErrors() { >> Errors<int>().bar(1); // expected-error{{bad i}} >> >> Errors<int>().fooOvl(0); >> - Errors<int>().fooOvl(1); // expected-error{{call to unavailable}} >> + Errors<int>().fooOvl(1); // expected-error{{int bad i}} >> Errors<int>().fooOvl(short(0)); >> - Errors<int>().fooOvl(short(1)); // expected-error{{call to >> unavailable}} >> + Errors<int>().fooOvl(short(1)); // expected-error{{short bad i}} >> >> Errors<int>().barOvl(0); >> - Errors<int>().barOvl(1); // expected-error{{call to unavailable}} >> + Errors<int>().barOvl(1); // expected-error{{int bad i}} >> Errors<int>().barOvl(short(0)); >> - Errors<int>().barOvl(short(1)); // expected-error{{call to >> unavailable}} >> + Errors<int>().barOvl(short(1)); // expected-error{{short bad i}} >> } >> >> template <typename T> >> @@ -275,8 +277,8 @@ namespace late_constexpr { >> constexpr int foo(); >> constexpr int foo(int a); >> >> -void bar() _diagnose_if(foo(), "bad foo", "error"); // >> expected-note{{from 'diagnose_if'}} expected-note{{not viable: requires 0 >> arguments}} >> -void bar(int a) _diagnose_if(foo(a), "bad foo", "error"); // >> expected-note{{bad foo}} >> +void bar() _diagnose_if(foo(), "bad foo", "error"); // >> expected-note{{from 'diagnose_if'}} >> +void bar(int a) _diagnose_if(foo(a), "bad foo", "error"); // >> expected-note{{from 'diagnose_if'}} >> >> void early() { >> bar(); >> @@ -290,7 +292,7 @@ constexpr int foo(int a) { return a; } >> void late() { >> bar(); // expected-error{{bad foo}} >> bar(0); >> - bar(1); // expected-error{{call to unavailable function}} >> + bar(1); // expected-error{{bad foo}} >> } >> } >> >> @@ -301,11 +303,11 @@ struct Foo { >> constexpr bool isFooable() const { return i; } >> >> void go() const _diagnose_if(isFooable(), "oh no", "error") {} // >> expected-note{{from 'diagnose_if'}} >> - operator int() const _diagnose_if(isFooable(), "oh no", "error") { >> return 1; } // expected-note{{oh no}} >> + operator int() const _diagnose_if(isFooable(), "oh no", "error") { >> return 1; } // expected-note{{from 'diagnose_if'}} >> >> - void go2() const _diagnose_if(isFooable(), "oh no", "error") // >> expected-note{{oh no}} >> + void go2() const _diagnose_if(isFooable(), "oh no", "error") // >> expected-note{{from 'diagnose_if'}} >> __attribute__((enable_if(true, ""))) {} >> - void go2() const _diagnose_if(isFooable(), "oh no", "error") {} // >> expected-note{{oh no}} >> + void go2() const _diagnose_if(isFooable(), "oh no", "error") {} >> >> constexpr int go3() const _diagnose_if(isFooable(), "oh no", "error") >> __attribute__((enable_if(true, ""))) { >> @@ -326,20 +328,20 @@ struct Foo { >> } >> }; >> >> -void go(const Foo &f) _diagnose_if(f.isFooable(), "oh no", "error") {} // >> expected-note{{oh no}} >> +void go(const Foo &f) _diagnose_if(f.isFooable(), "oh no", "error") {} // >> expected-note{{from 'diagnose_if'}} >> >> void run() { >> Foo(0).go(); >> Foo(1).go(); // expected-error{{oh no}} >> >> (void)int(Foo(0)); >> - (void)int(Foo(1)); // expected-error{{uses deleted function}} >> + (void)int(Foo(1)); // expected-error{{oh no}} >> >> Foo(0).go2(); >> - Foo(1).go2(); // expected-error{{call to unavailable member function}} >> + Foo(1).go2(); // expected-error{{oh no}} >> >> go(Foo(0)); >> - go(Foo(1)); // expected-error{{call to unavailable function}} >> + go(Foo(1)); // expected-error{{oh no}} >> } >> } >> >> @@ -349,17 +351,17 @@ struct Foo { >> constexpr Foo(int i): i(i) {} >> constexpr bool bad() const { return i; } >> >> - template <typename T> T getVal() _diagnose_if(bad(), "oh no", "error") >> { // expected-note{{oh no}} >> + template <typename T> T getVal() _diagnose_if(bad(), "oh no", "error") >> { // expected-note{{from 'diagnose_if'}} >> return T(); >> } >> >> template <typename T> >> - constexpr T getVal2() const _diagnose_if(bad(), "oh no", "error") { // >> expected-note{{oh no}} >> + constexpr T getVal2() const _diagnose_if(bad(), "oh no", "error") { // >> expected-note{{from 'diagnose_if'}} >> return T(); >> } >> >> template <typename T> >> - constexpr operator T() const _diagnose_if(bad(), "oh no", "error") { // >> expected-note{{oh no}} >> + constexpr operator T() const _diagnose_if(bad(), "oh no", "error") { // >> expected-note{{from 'diagnose_if'}} >> return T(); >> } >> >> @@ -369,13 +371,13 @@ struct Foo { >> >> void run() { >> Foo(0).getVal<int>(); >> - Foo(1).getVal<int>(); // expected-error{{call to unavailable member >> function}} >> + Foo(1).getVal<int>(); // expected-error{{oh no}} >> >> Foo(0).getVal2<int>(); >> - Foo(1).getVal2<int>(); // expected-error{{call to unavailable member >> function}} >> + Foo(1).getVal2<int>(); // expected-error{{oh no}} >> >> (void)int(Foo(0)); >> - (void)int(Foo(1)); // expected-error{{uses deleted function}} >> + (void)int(Foo(1)); // expected-error{{oh no}} >> } >> } >> >> @@ -385,18 +387,18 @@ struct Foo { >> int i; >> constexpr Foo(int i): i(i) {} >> constexpr bool bad() const { return i; } >> - const Bar *operator->() const _diagnose_if(bad(), "oh no", "error") { >> // expected-note{{oh no}} >> + const Bar *operator->() const _diagnose_if(bad(), "oh no", "error") { >> // expected-note{{from 'diagnose_if'}} >> return nullptr; >> } >> - void operator()() const _diagnose_if(bad(), "oh no", "error") {} // >> expected-note{{oh no}} >> + void operator()() const _diagnose_if(bad(), "oh no", "error") {} // >> expected-note{{from 'diagnose_if'}} >> }; >> >> struct ParenOverload { >> int i; >> constexpr ParenOverload(int i): i(i) {} >> constexpr bool bad() const { return i; } >> - void operator()(double) const _diagnose_if(bad(), "oh no", "error") {} >> // expected-note 2{{oh no}} >> - void operator()(int) const _diagnose_if(bad(), "oh no", "error") {} // >> expected-note 2{{oh no}} >> + void operator()(double) const _diagnose_if(bad(), "oh no", "error") {} >> // expected-note{{from 'diagnose_if'}} >> + void operator()(int) const _diagnose_if(bad(), "oh no", "error") {} // >> expected-note{{from 'diagnose_if'}} >> }; >> >> struct ParenTemplate { >> @@ -404,33 +406,70 @@ struct ParenTemplate { >> constexpr ParenTemplate(int i): i(i) {} >> constexpr bool bad() const { return i; } >> template <typename T> >> - void operator()(T) const _diagnose_if(bad(), "oh no", "error") {} // >> expected-note 2{{oh no}} >> + void operator()(T) const _diagnose_if(bad(), "oh no", "error") {} // >> expected-note 2{{from 'diagnose_if'}} >> }; >> >> void run() { >> (void)Foo(0)->j; >> - (void)Foo(1)->j; // expected-error{{selected unavailable operator >> '->'}} >> + (void)Foo(1)->j; // expected-error{{oh no}} >> >> Foo(0)(); >> - Foo(1)(); // expected-error{{unavailable function call operator}} >> + Foo(1)(); // expected-error{{oh no}} >> >> ParenOverload(0)(1); >> ParenOverload(0)(1.); >> >> - ParenOverload(1)(1); // expected-error{{unavailable function call >> operator}} >> - ParenOverload(1)(1.); // expected-error{{unavailable function call >> operator}} >> + ParenOverload(1)(1); // expected-error{{oh no}} >> + ParenOverload(1)(1.); // expected-error{{oh no}} >> >> ParenTemplate(0)(1); >> ParenTemplate(0)(1.); >> >> - ParenTemplate(1)(1); // expected-error{{unavailable function call >> operator}} >> - ParenTemplate(1)(1.); // expected-error{{unavailable function call >> operator}} >> + ParenTemplate(1)(1); // expected-error{{oh no}} >> + ParenTemplate(1)(1.); // expected-error{{oh no}} >> } >> >> void runLambda() { >> - auto L1 = [](int i) _diagnose_if(i, "oh no", "error") {}; // >> expected-note{{oh no}} expected-note{{conversion candidate}} >> + auto L1 = [](int i) _diagnose_if(i, "oh no", "error") {}; // >> expected-note{{from 'diagnose_if'}} >> L1(0); >> - L1(1); // expected-error{{call to unavailable function call}} >> + L1(1); // expected-error{{oh no}} >> +} >> + >> +struct Brackets { >> + int i; >> + constexpr Brackets(int i): i(i) {} >> + void operator[](int) _diagnose_if(i == 1, "oh no", "warning") // >> expected-note{{from 'diagnose_if'}} >> + _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from >> 'diagnose_if'}} >> +}; >> + >> +void runBrackets(int i) { >> + Brackets{0}[i]; >> + Brackets{1}[i]; // expected-warning{{oh no}} >> + Brackets{2}[i]; // expected-error{{oh no}} >> +} >> + >> +struct Unary { >> + int i; >> + constexpr Unary(int i): i(i) {} >> + void operator+() _diagnose_if(i == 1, "oh no", "warning") // >> expected-note{{from 'diagnose_if'}} >> + _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from >> 'diagnose_if'}} >> +}; >> + >> +void runUnary() { >> + +Unary{0}; >> + +Unary{1}; // expected-warning{{oh no}} >> + +Unary{2}; // expected-error{{oh no}} >> +} >> + >> +struct PostInc { >> + void operator++(int i) _diagnose_if(i == 1, "oh no", "warning") // >> expected-note{{from 'diagnose_if'}} >> + _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from >> 'diagnose_if'}} >> +}; >> + >> +void runPostInc() { >> + PostInc{}++; >> + PostInc{}.operator++(1); // expected-warning{{oh no}} >> + PostInc{}.operator++(2); // expected-error{{oh no}} >> } >> } >> >> @@ -439,22 +478,192 @@ struct Foo { >> int I; >> constexpr Foo(int I): I(I) {} >> >> - constexpr const Foo &operator=(const Foo &) const // expected-note >> 2{{disabled: oh no}} >> - _diagnose_if(I, "oh no", "error") { >> + constexpr const Foo &operator=(const Foo &) const >> + _diagnose_if(I, "oh no", "error") { // expected-note{{from >> 'diagnose_if'}} >> return *this; >> } >> >> - constexpr const Foo &operator=(const Foo &&) const // >> expected-note{{disabled: oh no}} expected-note{{no known conversion}} >> - _diagnose_if(I, "oh no", "error") { >> + constexpr const Foo &operator=(const Foo &&) const >> + _diagnose_if(I, "oh no", "error") { // expected-note{{from >> 'diagnose_if'}} >> return *this; >> } >> }; >> >> +struct Bar { >> + int I; >> + constexpr Bar(int I) _diagnose_if(I == 1, "oh no", "warning") // >> expected-note{{from 'diagnose_if'}} >> + _diagnose_if(I == 2, "oh no", "error"): I(I) {} // >> expected-note{{from 'diagnose_if'}} >> +}; >> + >> void run() { >> constexpr Foo F{0}; >> constexpr Foo F2{1}; >> >> - F2 = F; // expected-error{{selected unavailable operator}} >> - F2 = Foo{2}; // expected-error{{selected unavailable operator}} >> + F2 = F; // expected-error{{oh no}} >> + F2 = Foo{2}; // expected-error{{oh no}} >> + >> + Bar{0}; >> + Bar{1}; // expected-warning{{oh no}} >> + Bar{2}; // expected-error{{oh no}} >> +} >> +} >> + >> +namespace ref_init { >> +struct Bar {}; >> +struct Baz {}; >> +struct Foo { >> + int i; >> + constexpr Foo(int i): i(i) {} >> + operator const Bar &() const _diagnose_if(i, "oh no", "warning"); // >> expected-note{{from 'diagnose_if'}} >> + operator const Baz &() const _diagnose_if(i, "oh no", "error"); // >> expected-note{{from 'diagnose_if'}} >> +}; >> +void fooBar(const Bar &b); >> +void fooBaz(const Baz &b); >> + >> +void run() { >> + fooBar(Foo{0}); >> + fooBar(Foo{1}); // expected-warning{{oh no}} >> + fooBaz(Foo{0}); >> + fooBaz(Foo{1}); // expected-error{{oh no}} >> +} >> +} >> + >> +namespace udl { >> +void operator""_fn(char c)_diagnose_if(c == 1, "oh no", "warning") // >> expected-note{{from 'diagnose_if'}} >> + _diagnose_if(c == 2, "oh no", "error"); // expected-note{{from >> 'diagnose_if'}} >> + >> +void run() { >> + '\0'_fn; >> + '\1'_fn; // expected-warning{{oh no}} >> + '\2'_fn; // expected-error{{oh no}} >> +} >> +} >> + >> +namespace PR31638 { >> +struct String { >> + String(char const* __s) _diagnose_if(__s == nullptr, "oh no ptr", >> "warning"); // expected-note{{from 'diagnose_if'}} >> + String(int __s) _diagnose_if(__s != 0, "oh no int", "warning"); // >> expected-note{{from 'diagnose_if'}} >> +}; >> + >> +void run() { >> + String s(nullptr); // expected-warning{{oh no ptr}} >> + String ss(42); // expected-warning{{oh no int}} >> +} >> +} >> + >> +namespace PR31639 { >> +struct Foo { >> + Foo(int I) __attribute__((diagnose_if(I, "oh no", "error"))); // >> expected-note{{from 'diagnose_if'}} >> +}; >> + >> +void bar() { Foo f(1); } // expected-error{{oh no}} >> +} >> + >> +namespace user_defined_conversion { >> +struct Foo { >> + int i; >> + constexpr Foo(int i): i(i) {} >> + operator size_t() const _diagnose_if(i == 1, "oh no", "warning") // >> expected-note{{from 'diagnose_if'}} >> + _diagnose_if(i == 2, "oh no", "error"); // expected-note{{from >> 'diagnose_if'}} >> +}; >> + >> +void run() { >> + // `new T[N]`, where N is implicitly convertible to size_t, calls >> + // PerformImplicitConversion directly. This lets us test the diagnostic >> logic >> + // in PerformImplicitConversion. >> + new int[Foo{0}]; >> + new int[Foo{1}]; // expected-warning{{oh no}} >> + new int[Foo{2}]; // expected-error{{oh no}} >> +} >> +} >> + >> +namespace std { >> + template <typename T> >> + struct initializer_list { >> + const T *ptr; >> + size_t elems; >> + >> + constexpr size_t size() const { return elems; } >> + }; >> +} >> + >> +namespace initializer_lists { >> +struct Foo { >> + Foo(std::initializer_list<int> l) >> + _diagnose_if(l.size() == 1, "oh no", "warning") // >> expected-note{{from 'diagnose_if'}} >> + _diagnose_if(l.size() == 2, "oh no", "error") {} // >> expected-note{{from 'diagnose_if'}} >> +}; >> + >> +void run() { >> + Foo{std::initializer_list<int>{}}; >> + Foo{std::initializer_list<int>{1}}; // expected-warning{{oh no}} >> + Foo{std::initializer_list<int>{1, 2}}; // expected-error{{oh no}} >> + Foo{std::initializer_list<int>{1, 2, 3}}; >> +} >> +} >> + >> +namespace range_for_loop { >> + namespace adl { >> + struct Foo { >> + int i; >> + constexpr Foo(int i): i(i) {} >> + }; >> + void **begin(const Foo &f) _diagnose_if(f.i, "oh no", "warning"); >> + void **end(const Foo &f) _diagnose_if(f.i, "oh no", "warning"); >> + >> + struct Bar { >> + int i; >> + constexpr Bar(int i): i(i) {} >> + }; >> + void **begin(const Bar &b) _diagnose_if(b.i, "oh no", "error"); >> + void **end(const Bar &b) _diagnose_if(b.i, "oh no", "error"); >> + } >> + >> + void run() { >> + for (void *p : adl::Foo(0)) {} >> + // FIXME: This should emit diagnostics. It seems that our constexpr >> + // evaluator isn't able to evaluate `adl::Foo(1)` as a constant, >> though. >> + for (void *p : adl::Foo(1)) {} >> + >> + for (void *p : adl::Bar(0)) {} >> + // FIXME: Same thing. >> + for (void *p : adl::Bar(1)) {} >> + } >> +} >> + >> +namespace operator_new { >> +struct Foo { >> + int j; >> + static void *operator new(size_t i) _diagnose_if(i, "oh no", >> "warning"); >> +}; >> + >> +struct Bar { >> + int j; >> + static void *operator new(size_t i) _diagnose_if(!i, "oh no", >> "warning"); >> +}; >> + >> +void run() { >> + // FIXME: This should emit a diagnostic. >> + new Foo(); >> + // This is here because we sometimes pass a dummy argument `operator >> new`. We >> + // should ignore this, rather than complaining about it. >> + new Bar(); >> +} >> +} >> + >> +namespace contextual_implicit_conv { >> +struct Foo { >> + int i; >> + constexpr Foo(int i): i(i) {} >> + constexpr operator int() const _diagnose_if(i == 1, "oh no", "warning") >> // expected-note{{from 'diagnose_if'}} >> + _diagnose_if(i == 2, "oh no", "error") { // expected-note{{from >> 'diagnose_if'}} >> + return i; >> + } >> +}; >> + >> +void run() { >> + switch (constexpr Foo i = 0) { default: break; } >> + switch (constexpr Foo i = 1) { default: break; } // >> expected-warning{{oh no}} >> + switch (constexpr Foo i = 2) { default: break; } // expected-error{{oh >> no}} >> } >> } >> >> >> _______________________________________________ >> cfe-commits mailing list >> cfe-commits@lists.llvm.org >> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > > _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits