<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>