Commit ccd67298 authored by Hans Wennborg's avatar Hans Wennborg
Browse files

Merging r293360:

------------------------------------------------------------------------
r293360 | gbiv | 2017-01-27 18:19:40 -0800 (Fri, 27 Jan 2017) | 11 lines

Change how we handle diagnose_if attributes.

This patch changes how we handle argument-dependent `diagnose_if`
attributes. In particular, we now check them in the same place that we
check for things like passing NULL to Nonnull args, etc. This is
basically better in every way than how we were handling them before. :)

This fixes PR31638, PR31639, and PR31640.

Differential Revision: https://reviews.llvm.org/D28889

------------------------------------------------------------------------
Merging r293369:
------------------------------------------------------------------------
r293369 | gbiv | 2017-01-27 20:16:32 -0800 (Fri, 27 Jan 2017) | 7 lines

Attempt to unbreak buildbots.

r293360 broke some ARM bots, because size_t on those targets is
apparently `unsigned int`, not `unsigned long`. `sizeof(whatever)`
should to give us a `size_t`, so we can just use the type of that
instead.

------------------------------------------------------------------------


git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_40@293784 91177308-0d34-0410-b5e6-96231b3b80d8
parent 5eb0ba0f
......@@ -675,26 +675,6 @@ namespace clang {
/// to be used while performing partial ordering of function templates.
unsigned ExplicitCallArguments;
/// The number of diagnose_if attributes that this overload triggered.
/// If any of the triggered attributes are errors, this won't count
/// diagnose_if warnings.
unsigned NumTriggeredDiagnoseIfs = 0;
/// Basically a TinyPtrVector<DiagnoseIfAttr *> that doesn't own the vector:
/// If NumTriggeredDiagnoseIfs is 0 or 1, this is a DiagnoseIfAttr *,
/// otherwise it's a pointer to an array of `NumTriggeredDiagnoseIfs`
/// DiagnoseIfAttr *s.
llvm::PointerUnion<DiagnoseIfAttr *, DiagnoseIfAttr **> DiagnoseIfInfo;
/// Gets an ArrayRef for the data at DiagnoseIfInfo. Note that this may give
/// you a pointer into DiagnoseIfInfo.
ArrayRef<DiagnoseIfAttr *> getDiagnoseIfInfo() const {
auto *Ptr = NumTriggeredDiagnoseIfs <= 1
? DiagnoseIfInfo.getAddrOfPtr1()
: DiagnoseIfInfo.get<DiagnoseIfAttr **>();
return {Ptr, NumTriggeredDiagnoseIfs};
}
union {
DeductionFailureInfo DeductionFailure;
......@@ -759,9 +739,8 @@ namespace clang {
SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<Decl *, 16> Functions;
// Allocator for ConversionSequenceLists and DiagnoseIfAttr* arrays.
// We store the first few of each of these inline to avoid allocation for
// small sets.
// Allocator for ConversionSequenceLists. We store the first few of these
// inline to avoid allocation for small sets.
llvm::BumpPtrAllocator SlabAllocator;
SourceLocation Loc;
......@@ -776,6 +755,8 @@ namespace clang {
/// from the slab allocator.
/// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
/// instead.
/// FIXME: Now that this only allocates ImplicitConversionSequences, do we
/// want to un-generalize this?
template <typename T>
T *slabAllocate(unsigned N) {
// It's simpler if this doesn't need to consider alignment.
......@@ -809,11 +790,6 @@ namespace clang {
SourceLocation getLocation() const { return Loc; }
CandidateSetKind getKind() const { return Kind; }
/// Make a DiagnoseIfAttr* array in a block of memory that will live for
/// as long as this OverloadCandidateSet. Returns a pointer to the start
/// of that array.
DiagnoseIfAttr **addDiagnoseIfComplaints(ArrayRef<DiagnoseIfAttr *> CA);
/// \brief Determine when this overload candidate will be new to the
/// overload set.
bool isNewCandidate(Decl *F) {
......
......@@ -2532,14 +2532,14 @@ public:
void AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr::Classification ObjectClassification,
Expr *ThisArg, ArrayRef<Expr *> Args,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversion = false);
void AddMethodCandidate(CXXMethodDecl *Method,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
Expr *ThisArg, ArrayRef<Expr *> Args,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool PartialOverloading = false,
......@@ -2550,7 +2550,6 @@ public:
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
Expr *ThisArg,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
......@@ -2624,37 +2623,27 @@ public:
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
bool MissingImplicitThis = false);
/// Check the diagnose_if attributes on the given function. Returns the
/// first succesful fatal attribute, or null if calling Function(Args) isn't
/// an error.
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
/// non-ArgDependent DiagnoseIfAttrs.
///
/// This only considers ArgDependent DiagnoseIfAttrs.
/// Argument-dependent diagnose_if attributes should be checked each time a
/// function is used as a direct callee of a function call.
///
/// This will populate Nonfatal with all non-error DiagnoseIfAttrs that
/// succeed. If this function returns non-null, the contents of Nonfatal are
/// unspecified.
DiagnoseIfAttr *
checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
bool MissingImplicitThis = false,
Expr *ThisArg = nullptr);
/// Returns true if any errors were emitted.
bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
const Expr *ThisArg,
ArrayRef<const Expr *> Args,
SourceLocation Loc);
/// Check the diagnose_if expressions on the given function. Returns the
/// first succesful fatal attribute, or null if using Function isn't
/// an error.
/// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
/// ArgDependent DiagnoseIfAttrs.
///
/// This ignores all ArgDependent DiagnoseIfAttrs.
/// Argument-independent diagnose_if attributes should be checked on every use
/// of a function.
///
/// This will populate Nonfatal with all non-error DiagnoseIfAttrs that
/// succeed. If this function returns non-null, the contents of Nonfatal are
/// unspecified.
DiagnoseIfAttr *
checkArgIndependentDiagnoseIf(FunctionDecl *Function,
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal);
/// Emits the diagnostic contained in the given DiagnoseIfAttr at Loc. Also
/// emits a note about the location of said attribute.
void emitDiagnoseIfDiagnostic(SourceLocation Loc, const DiagnoseIfAttr *DIA);
/// Returns true if any errors were emitted.
bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
SourceLocation Loc);
/// Returns whether the given function's address can be taken or not,
/// optionally emitting a diagnostic if the address can't be taken.
......@@ -9914,8 +9903,8 @@ private:
SourceLocation Loc);
void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
ArrayRef<const Expr *> Args, bool IsMemberFunction,
SourceLocation Loc, SourceRange Range,
const Expr *ThisArg, ArrayRef<const Expr *> Args,
bool IsMemberFunction, SourceLocation Loc, SourceRange Range,
VariadicCallType CallType);
bool CheckObjCString(Expr *Arg);
......
......@@ -2426,11 +2426,12 @@ static void CheckNonNullArguments(Sema &S,
}
/// Handles the checks for format strings, non-POD arguments to vararg
/// functions, and NULL arguments passed to non-NULL parameters.
/// functions, NULL arguments passed to non-NULL parameters, and diagnose_if
/// attributes.
void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
ArrayRef<const Expr *> Args, bool IsMemberFunction,
SourceLocation Loc, SourceRange Range,
VariadicCallType CallType) {
const Expr *ThisArg, ArrayRef<const Expr *> Args,
bool IsMemberFunction, SourceLocation Loc,
SourceRange Range, VariadicCallType CallType) {
// FIXME: We should check as much as we can in the template definition.
if (CurContext->isDependentContext())
return;
......@@ -2477,6 +2478,9 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
CheckArgumentWithTypeTag(I, Args.data());
}
}
if (FD)
diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
}
/// CheckConstructorCall - Check a constructor call for correctness and safety
......@@ -2487,8 +2491,8 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl,
SourceLocation Loc) {
VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
checkCall(FDecl, Proto, Args, /*IsMemberFunction=*/true, Loc, SourceRange(),
CallType);
checkCall(FDecl, Proto, /*ThisArg=*/nullptr, Args, /*IsMemberFunction=*/true,
Loc, SourceRange(), CallType);
}
/// CheckFunctionCall - Check a direct function call for various correctness
......@@ -2503,14 +2507,20 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
TheCall->getCallee());
Expr** Args = TheCall->getArgs();
unsigned NumArgs = TheCall->getNumArgs();
Expr *ImplicitThis = nullptr;
if (IsMemberOperatorCall) {
// If this is a call to a member operator, hide the first argument
// from checkCall.
// FIXME: Our choice of AST representation here is less than ideal.
ImplicitThis = Args[0];
++Args;
--NumArgs;
}
checkCall(FDecl, Proto, llvm::makeArrayRef(Args, NumArgs),
} else if (IsMemberFunction)
ImplicitThis =
cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();
checkCall(FDecl, Proto, ImplicitThis, llvm::makeArrayRef(Args, NumArgs),
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
......@@ -2546,8 +2556,8 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
VariadicCallType CallType =
Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
checkCall(Method, nullptr, Args,
/*IsMemberFunction=*/false, lbrac, Method->getSourceRange(),
checkCall(Method, nullptr, /*ThisArg=*/nullptr, Args,
/*IsMemberFunction=*/false, lbrac, Method->getSourceRange(),
CallType);
return false;
......@@ -2576,7 +2586,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
CallType = VariadicFunction;
}
checkCall(NDecl, Proto,
checkCall(NDecl, Proto, /*ThisArg=*/nullptr,
llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
......@@ -2589,7 +2599,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
TheCall->getCallee());
checkCall(/*FDecl=*/nullptr, Proto,
checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr,
llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
/*IsMemberFunction=*/false, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
......
......@@ -342,7 +342,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
}
 
// See if this is a deleted function.
SmallVector<DiagnoseIfAttr *, 4> DiagnoseIfWarnings;
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
......@@ -365,11 +364,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD))
return true;
 
if (const DiagnoseIfAttr *A =
checkArgIndependentDiagnoseIf(FD, DiagnoseIfWarnings)) {
emitDiagnoseIfDiagnostic(Loc, A);
if (diagnoseArgIndependentDiagnoseIfAttrs(FD, Loc))
return true;
}
}
 
// [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
......@@ -385,9 +381,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
return true;
}
 
for (const auto *W : DiagnoseIfWarnings)
emitDiagnoseIfDiagnostic(Loc, W);
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
ObjCPropertyAccess);
 
......@@ -5189,16 +5182,6 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn,
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
return;
}
SmallVector<DiagnoseIfAttr *, 4> Nonfatal;
if (const DiagnoseIfAttr *Attr = S.checkArgDependentDiagnoseIf(
Callee, ArgExprs, Nonfatal, /*MissingImplicitThis=*/true)) {
S.emitDiagnoseIfDiagnostic(Fn->getLocStart(), Attr);
return;
}
for (const auto *W : Nonfatal)
S.emitDiagnoseIfDiagnostic(Fn->getLocStart(), W);
}
 
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
......
......@@ -6712,6 +6712,11 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
CXXMemberCallExpr *CE =
new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK,
Exp.get()->getLocEnd());
if (CheckFunctionCall(Method, CE,
Method->getType()->castAs<FunctionProtoType>()))
return ExprError();
return CE;
}
......
......@@ -2960,7 +2960,6 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
/*ThisArg=*/nullptr,
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
......@@ -2973,7 +2972,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
AddMethodTemplateCandidate(
Tmpl, Cand, RD, nullptr, ThisTy, Classification,
/*ThisArg=*/nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
AddTemplateOverloadCandidate(
CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
......
This diff is collapsed.
......@@ -70,14 +70,14 @@ void runVariable() {
#define _overloadable __attribute__((overloadable))
int ovl1(const char *n) _overloadable _diagnose_if(n, "oh no", "error"); // expected-note{{oh no}}
int ovl1(void *m) _overloadable; // expected-note{{candidate function}}
int ovl1(const char *n) _overloadable _diagnose_if(n, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
int ovl1(void *m) _overloadable;
int ovl2(const char *n) _overloadable _diagnose_if(n, "oh no", "error"); // expected-note{{candidate function}}
int ovl2(char *m) _overloadable; // expected-note{{candidate function}}
void overloadsYay() {
ovl1((void *)0);
ovl1(""); // expected-error{{call to unavailable function}}
ovl1(""); // expected-error{{oh no}}
ovl2((void *)0); // expected-error{{ambiguous}}
}
......
......@@ -2,6 +2,8 @@
#define _diagnose_if(...) __attribute__((diagnose_if(__VA_ARGS__)))
using size_t = decltype(sizeof(int));
namespace type_dependent {
template <typename T>
void neverok() _diagnose_if(!T(), "oh no", "error") {} // expected-note 4{{from 'diagnose_if'}}
......@@ -51,14 +53,14 @@ void runAll() {
}
template <typename T>
void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // expected-note {{candidate disabled: oh no}}
void errorIf(T a) _diagnose_if(T() != a, "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
template <typename T>
void warnIf(T a) _diagnose_if(T() != a, "oh no", "warning") {} // expected-note {{from 'diagnose_if'}}
void warnIf(T a) _diagnose_if(T() != a, "oh no", "warning") {} // expected-note{{from 'diagnose_if'}}
void runIf() {
errorIf(0);
errorIf(1); // expected-error{{call to unavailable function}}
errorIf(1); // expected-error{{oh no}}
warnIf(0);
warnIf(1); // expected-warning{{oh no}}
......@@ -114,14 +116,14 @@ void runAll() {
}
template <int N>
void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // expected-note {{candidate disabled: oh no}}
void errorIf(int a) _diagnose_if(N != a, "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
template <int N>
void warnIf(int a) _diagnose_if(N != a, "oh no", "warning") {} // expected-note {{from 'diagnose_if'}}
void warnIf(int a) _diagnose_if(N != a, "oh no", "warning") {} // expected-note{{from 'diagnose_if'}}
void runIf() {
errorIf<0>(0);
errorIf<0>(1); // expected-error{{call to unavailable function}}
errorIf<0>(1); // expected-error{{oh no}}
warnIf<0>(0);
warnIf<0>(1); // expected-warning{{oh no}}
......@@ -135,8 +137,8 @@ void foo(short);
void bar(int);
void bar(short) _diagnose_if(1, "oh no", "error");
void fooArg(int a) _diagnose_if(a, "oh no", "error"); // expected-note{{candidate disabled: oh no}}
void fooArg(short); // expected-note{{candidate function}}
void fooArg(int a) _diagnose_if(a, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
void fooArg(short);
void barArg(int);
void barArg(short a) _diagnose_if(a, "oh no", "error");
......@@ -145,7 +147,7 @@ void runAll() {
foo(1); // expected-error{{oh no}}
bar(1);
fooArg(1); // expected-error{{call to unavailable function}}
fooArg(1); // expected-error{{oh no}}
barArg(1);
auto p = foo; // expected-error{{incompatible initializer of type '<overloaded function type>'}}
......@@ -188,11 +190,11 @@ struct Errors {
void foo(int i) _diagnose_if(i, "bad i", "error"); // expected-note{{from 'diagnose_if'}}
void bar(int i) _diagnose_if(i != T(), "bad i", "error"); // expected-note{{from 'diagnose_if'}}
void fooOvl(int i) _diagnose_if(i, "int bad i", "error"); // expected-note 2{{int bad i}}
void fooOvl(short i) _diagnose_if(i, "short bad i", "error"); // expected-note 2{{short bad i}}
void fooOvl(int i) _diagnose_if(i, "int bad i", "error"); // expected-note{{from 'diagnose_if'}}
void fooOvl(short i) _diagnose_if(i, "short bad i", "error"); // expected-note{{from 'diagnose_if'}}
void barOvl(int i) _diagnose_if(i != T(), "int bad i", "error"); // expected-note 2{{int bad i}}
void barOvl(short i) _diagnose_if(i != T(), "short bad i", "error"); // expected-note 2{{short bad i}}
void barOvl(int i) _diagnose_if(i != T(), "int bad i", "error"); // expected-note{{from 'diagnose_if'}}
void barOvl(short i) _diagnose_if(i != T(), "short bad i", "error"); // expected-note{{from 'diagnose_if'}}
};
void runErrors() {
......@@ -203,14 +205,14 @@ void runErrors() {
Errors<int>().bar(1); // expected-error{{bad i}}
Errors<int>().fooOvl(0);
Errors<int>().fooOvl(1); // expected-error{{call to unavailable}}
Errors<int>().fooOvl(1); // expected-error{{int bad i}}
Errors<int>().fooOvl(short(0));
Errors<int>().fooOvl(short(1)); // expected-error{{call to unavailable}}
Errors<int>().fooOvl(short(1)); // expected-error{{short bad i}}
Errors<int>().barOvl(0);
Errors<int>().barOvl(1); // expected-error{{call to unavailable}}
Errors<int>().barOvl(1); // expected-error{{int bad i}}
Errors<int>().barOvl(short(0));
Errors<int>().barOvl(short(1)); // expected-error{{call to unavailable}}
Errors<int>().barOvl(short(1)); // expected-error{{short bad i}}
}
template <typename T>
......@@ -275,8 +277,8 @@ namespace late_constexpr {
constexpr int foo();
constexpr int foo(int a);
void bar() _diagnose_if(foo(), "bad foo", "error"); // expected-note{{from 'diagnose_if'}} expected-note{{not viable: requires 0 arguments}}
void bar(int a) _diagnose_if(foo(a), "bad foo", "error"); // expected-note{{bad foo}}
void bar() _diagnose_if(foo(), "bad foo", "error"); // expected-note{{from 'diagnose_if'}}
void bar(int a) _diagnose_if(foo(a), "bad foo", "error"); // expected-note{{from 'diagnose_if'}}
void early() {
bar();
......@@ -290,7 +292,7 @@ constexpr int foo(int a) { return a; }
void late() {
bar(); // expected-error{{bad foo}}
bar(0);
bar(1); // expected-error{{call to unavailable function}}
bar(1); // expected-error{{bad foo}}
}
}
......@@ -301,11 +303,11 @@ struct Foo {
constexpr bool isFooable() const { return i; }
void go() const _diagnose_if(isFooable(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
operator int() const _diagnose_if(isFooable(), "oh no", "error") { return 1; } // expected-note{{oh no}}
operator int() const _diagnose_if(isFooable(), "oh no", "error") { return 1; } // expected-note{{from 'diagnose_if'}}
void go2() const _diagnose_if(isFooable(), "oh no", "error") // expected-note{{oh no}}
void go2() const _diagnose_if(isFooable(), "oh no", "error") // expected-note{{from 'diagnose_if'}}
__attribute__((enable_if(true, ""))) {}
void go2() const _diagnose_if(isFooable(), "oh no", "error") {} // expected-note{{oh no}}
void go2() const _diagnose_if(isFooable(), "oh no", "error") {}
constexpr int go3() const _diagnose_if(isFooable(), "oh no", "error")
__attribute__((enable_if(true, ""))) {
......@@ -326,20 +328,20 @@ struct Foo {
}
};
void go(const Foo &f) _diagnose_if(f.isFooable(), "oh no", "error") {} // expected-note{{oh no}}
void go(const Foo &f) _diagnose_if(f.isFooable(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
void run() {
Foo(0).go();
Foo(1).go(); // expected-error{{oh no}}
(void)int(Foo(0));
(void)int(Foo(1)); // expected-error{{uses deleted function}}
(void)int(Foo(1)); // expected-error{{oh no}}
Foo(0).go2();
Foo(1).go2(); // expected-error{{call to unavailable member function}}
Foo(1).go2(); // expected-error{{oh no}}
go(Foo(0));
go(Foo(1)); // expected-error{{call to unavailable function}}
go(Foo(1)); // expected-error{{oh no}}
}
}
......@@ -349,17 +351,17 @@ struct Foo {
constexpr Foo(int i): i(i) {}
constexpr bool bad() const { return i; }
template <typename T> T getVal() _diagnose_if(bad(), "oh no", "error") { // expected-note{{oh no}}
template <typename T> T getVal() _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}}
return T();
}
template <typename T>
constexpr T getVal2() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{oh no}}
constexpr T getVal2() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}}
return T();
}
template <typename T>
constexpr operator T() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{oh no}}
constexpr operator T() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}}
return T();
}
......@@ -369,13 +371,13 @@ struct Foo {
void run() {
Foo(0).getVal<int>();
Foo(1).getVal<int>(); // expected-error{{call to unavailable member function}}
Foo(1).getVal<int>(); // expected-error{{oh no}}
Foo(0).getVal2<int>();
Foo(1).getVal2<int>(); // expected-error{{call to unavailable member function}}
Foo(1).getVal2<int>(); // expected-error{{oh no}}
(void)int(Foo(0));
(void)int(Foo(1)); // expected-error{{uses deleted function}}
(void)int(Foo(1)); // expected-error{{oh no}}
}
}
......@@ -385,18 +387,18 @@ struct Foo {
int i;
constexpr Foo(int i): i(i) {}
constexpr bool bad() const { return i; }
const Bar *operator->() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{oh no}}
const Bar *operator->() const _diagnose_if(bad(), "oh no", "error") { // expected-note{{from 'diagnose_if'}}
return nullptr;
}
void operator()() const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{oh no}}
void operator()() const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
};
struct ParenOverload {
int i;
constexpr ParenOverload(int i): i(i) {}
constexpr bool bad() const { return i; }
void operator()(double) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{oh no}}
void operator()(int) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{oh no}}
void operator()(double) const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
void operator()(int) const _diagnose_if(bad(), "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
};
struct ParenTemplate {
......@@ -404,33 +406,70 @@ struct ParenTemplate {
constexpr ParenTemplate(int i): i(i) {}
constexpr bool bad() const { return i; }
template <typename T>
void operator()(T) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{oh no}}
void operator()(T) const _diagnose_if(bad(), "oh no", "error") {} // expected-note 2{{from 'diagnose_if'}}
};
void run() {
(void)Foo(0)->j;
(void)Foo(1)->j; // expected-error{{selected unavailable operator '->'}}
(void)Foo(1)->j; // expected-error{{oh no}}
Foo(0)();
Foo(1)(); // expected-error{{unavailable function call operator}}
Foo(1)(); // expected-error{{oh no}}
ParenOverload(0)(1);
ParenOverload(0)(1.);
ParenOverload(1)(1); // expected-error{{unavailable function call operator}}
ParenOverload(1)(1.); // expected-error{{unavailable function call operator}}
ParenOverload(1)(1); // expected-error{{oh no}}
ParenOverload(1)(1.); // expected-error{{oh no}}
ParenTemplate(0)(1);
ParenTemplate(0)(1.);
ParenTemplate(1)(1); // expected-error{{unavailable function call operator}}
ParenTemplate(1)(1.); // expected-error{{unavailable function call operator}}
ParenTemplate(1)(1); // expected-error{{oh no}}
ParenTemplate(1)(1.); // expected-error{{oh no}}
}
void runLambda() {
auto L1 = [](int i) _diagnose_if(i, "oh no", "error") {}; // expected-note{{oh no}} expected-note{{conversion candidate}}
auto L1 = [](int i) _diagnose_if(i, "oh no", "error") {}; // expected-note{{from 'diagnose_if'}}
L1(0);
L1(1); // expected-error{{call to unavailable function call}}
L1(1); // expected-error{{oh no}}
}
struct Brackets {
int i;
constexpr Brackets(int i): i(i) {}
void operator[](int) _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
_diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
};
void runBrackets(int i) {
Brackets{0}[i];
Brackets{1}[i]; // expected-warning{{oh no}}
Brackets{2}[i]; // expected-error{{oh no}}
}
struct Unary {
int i;
constexpr Unary(int i): i(i) {}
void operator+() _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
_diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
};
void runUnary() {
+Unary{0};
+Unary{1}; // expected-warning{{oh no}}
+Unary{2}; // expected-error{{oh no}}
}