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