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