r293360 - Change how we handle diagnose_if attributes.
Hans Wennborg via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 1 09:25:55 PST 2017
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.iv at 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 at 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 at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>
More information about the cfe-commits
mailing list