Vendor import of clang release_40 branch r293807:

https://llvm.org/svn/llvm-project/cfe/branches/release_40@293807
This commit is contained in:
Dimitry Andric 2017-02-01 21:35:00 +00:00
parent d1b6c770be
commit 1230633774
20 changed files with 530 additions and 348 deletions

View File

@ -3827,13 +3827,13 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
friend class ASTContext; // creates these
AttributedType(QualType canon, Kind attrKind,
QualType modified, QualType equivalent)
: Type(Attributed, canon, canon->isDependentType(),
canon->isInstantiationDependentType(),
canon->isVariablyModifiedType(),
canon->containsUnexpandedParameterPack()),
ModifiedType(modified), EquivalentType(equivalent) {
AttributedType(QualType canon, Kind attrKind, QualType modified,
QualType equivalent)
: Type(Attributed, canon, equivalent->isDependentType(),
equivalent->isInstantiationDependentType(),
equivalent->isVariablyModifiedType(),
equivalent->containsUnexpandedParameterPack()),
ModifiedType(modified), EquivalentType(equivalent) {
AttributedTypeBits.AttrKind = attrKind;
}

View File

@ -3373,7 +3373,8 @@ def note_ovl_candidate_has_pass_object_size_params: Note<
"candidate address cannot be taken because parameter %0 has "
"pass_object_size attribute">;
def err_diagnose_if_succeeded : Error<"%0">;
def warn_diagnose_if_succeeded : Warning<"%0">, InGroup<UserDefinedWarnings>;
def warn_diagnose_if_succeeded : Warning<"%0">, InGroup<UserDefinedWarnings>,
ShowInSystemHeader;
def note_ovl_candidate_disabled_by_function_cond_attr : Note<
"candidate disabled: %0">;
def note_ovl_candidate_disabled_by_extension : Note<

View File

@ -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) {

View File

@ -2532,14 +2532,14 @@ class Sema {
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 @@ class Sema {
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
Expr *ThisArg,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
@ -2624,37 +2623,27 @@ class Sema {
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 @@ class Sema {
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);

View File

@ -2362,7 +2362,14 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
/// Extract the value of a character from a string literal.
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
uint64_t Index) {
// FIXME: Support ObjCEncodeExpr, MakeStringConstant
// FIXME: Support MakeStringConstant
if (const auto *ObjCEnc = dyn_cast<ObjCEncodeExpr>(Lit)) {
std::string Str;
Info.Ctx.getObjCEncodingForType(ObjCEnc->getEncodedType(), Str);
assert(Index <= Str.size() && "Index too large");
return APSInt::getUnsigned(Str.c_str()[Index]);
}
if (auto PE = dyn_cast<PredefinedExpr>(Lit))
Lit = PE->getFunctionName();
const StringLiteral *S = cast<StringLiteral>(Lit);

View File

@ -737,7 +737,7 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) {
}
bool CodeGenTypes::isPointerZeroInitializable(QualType T) {
assert (T->isAnyPointerType() && "Invalid type");
assert((T->isAnyPointerType() || T->isBlockPointerType()) && "Invalid type");
return isZeroInitializable(T);
}

View File

@ -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);

View File

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

View File

@ -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;
}

View File

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

View File

@ -839,20 +839,12 @@ void OverloadCandidateSet::destroyCandidates() {
void OverloadCandidateSet::clear() {
destroyCandidates();
// DiagnoseIfAttrs are just pointers, so we don't need to destroy them.
SlabAllocator.Reset();
NumInlineBytesUsed = 0;
Candidates.clear();
Functions.clear();
}
DiagnoseIfAttr **
OverloadCandidateSet::addDiagnoseIfComplaints(ArrayRef<DiagnoseIfAttr *> CA) {
auto *DIA = slabAllocate<DiagnoseIfAttr *>(CA.size());
std::uninitialized_copy(CA.begin(), CA.end(), DIA);
return DIA;
}
namespace {
class UnbridgedCastsSet {
struct Entry {
@ -5831,28 +5823,6 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
return false;
}
static void initDiagnoseIfComplaint(Sema &S, OverloadCandidateSet &CandidateSet,
OverloadCandidate &Candidate,
FunctionDecl *Function,
ArrayRef<Expr *> Args,
bool MissingImplicitThis = false,
Expr *ExplicitThis = nullptr) {
SmallVector<DiagnoseIfAttr *, 8> Results;
if (DiagnoseIfAttr *DIA = S.checkArgDependentDiagnoseIf(
Function, Args, Results, MissingImplicitThis, ExplicitThis)) {
Results.clear();
Results.push_back(DIA);
}
Candidate.NumTriggeredDiagnoseIfs = Results.size();
if (Results.empty())
Candidate.DiagnoseIfInfo = nullptr;
else if (Results.size() == 1)
Candidate.DiagnoseIfInfo = Results[0];
else
Candidate.DiagnoseIfInfo = CandidateSet.addDiagnoseIfComplaints(Results);
}
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
@ -5886,10 +5856,9 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
// object argument (C++ [over.call.func]p3), and the acting context
// is irrelevant.
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
Expr::Classification::makeSimpleLValue(),
/*ThisArg=*/nullptr, Args, CandidateSet,
SuppressUserConversions, PartialOverloading,
EarlyConversions);
Expr::Classification::makeSimpleLValue(), Args,
CandidateSet, SuppressUserConversions,
PartialOverloading, EarlyConversions);
return;
}
// We treat a constructor like a non-member function, since its object
@ -6050,8 +6019,6 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
Candidate.FailureKind = ovl_fail_ext_disabled;
return;
}
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Function, Args);
}
ObjCMethodDecl *
@ -6260,85 +6227,73 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
return nullptr;
}
static bool gatherDiagnoseIfAttrs(FunctionDecl *Function, bool ArgDependent,
SmallVectorImpl<DiagnoseIfAttr *> &Errors,
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal) {
for (auto *DIA : Function->specific_attrs<DiagnoseIfAttr>())
if (ArgDependent == DIA->getArgDependent()) {
if (DIA->isError())
Errors.push_back(DIA);
else
Nonfatal.push_back(DIA);
}
return !Errors.empty() || !Nonfatal.empty();
}
template <typename CheckFn>
static DiagnoseIfAttr *
checkDiagnoseIfAttrsWith(const SmallVectorImpl<DiagnoseIfAttr *> &Errors,
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
CheckFn &&IsSuccessful) {
static bool diagnoseDiagnoseIfAttrsWith(Sema &S, const FunctionDecl *FD,
bool ArgDependent, SourceLocation Loc,
CheckFn &&IsSuccessful) {
SmallVector<const DiagnoseIfAttr *, 8> Attrs;
for (const auto *DIA : FD->specific_attrs<DiagnoseIfAttr>()) {
if (ArgDependent == DIA->getArgDependent())
Attrs.push_back(DIA);
}
// Common case: No diagnose_if attributes, so we can quit early.
if (Attrs.empty())
return false;
auto WarningBegin = std::stable_partition(
Attrs.begin(), Attrs.end(),
[](const DiagnoseIfAttr *DIA) { return DIA->isError(); });
// Note that diagnose_if attributes are late-parsed, so they appear in the
// correct order (unlike enable_if attributes).
auto ErrAttr = llvm::find_if(Errors, IsSuccessful);
if (ErrAttr != Errors.end())
return *ErrAttr;
auto ErrAttr = llvm::find_if(llvm::make_range(Attrs.begin(), WarningBegin),
IsSuccessful);
if (ErrAttr != WarningBegin) {
const DiagnoseIfAttr *DIA = *ErrAttr;
S.Diag(Loc, diag::err_diagnose_if_succeeded) << DIA->getMessage();
S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
<< DIA->getParent() << DIA->getCond()->getSourceRange();
return true;
}
llvm::erase_if(Nonfatal, [&](DiagnoseIfAttr *A) { return !IsSuccessful(A); });
return nullptr;
for (const auto *DIA : llvm::make_range(WarningBegin, Attrs.end()))
if (IsSuccessful(DIA)) {
S.Diag(Loc, diag::warn_diagnose_if_succeeded) << DIA->getMessage();
S.Diag(DIA->getLocation(), diag::note_from_diagnose_if)
<< DIA->getParent() << DIA->getCond()->getSourceRange();
}
return false;
}
DiagnoseIfAttr *
Sema::checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal,
bool MissingImplicitThis,
Expr *ThisArg) {
SmallVector<DiagnoseIfAttr *, 4> Errors;
if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/true, Errors, Nonfatal))
return nullptr;
SFINAETrap Trap(*this);
SmallVector<Expr *, 16> ConvertedArgs;
Expr *ConvertedThis;
if (!convertArgsForAvailabilityChecks(*this, Function, ThisArg, Args, Trap,
MissingImplicitThis, ConvertedThis,
ConvertedArgs))
return nullptr;
return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr *DIA) {
APValue Result;
// It's sane to use the same ConvertedArgs for any redecl of this function,
// since EvaluateWithSubstitution only cares about the position of each
// argument in the arg list, not the ParmVarDecl* it maps to.
if (!DIA->getCond()->EvaluateWithSubstitution(
Result, Context, DIA->getParent(), ConvertedArgs, ConvertedThis))
return false;
return Result.isInt() && Result.getInt().getBoolValue();
});
bool Sema::diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function,
const Expr *ThisArg,
ArrayRef<const Expr *> Args,
SourceLocation Loc) {
return diagnoseDiagnoseIfAttrsWith(
*this, Function, /*ArgDependent=*/true, Loc,
[&](const DiagnoseIfAttr *DIA) {
APValue Result;
// It's sane to use the same Args for any redecl of this function, since
// EvaluateWithSubstitution only cares about the position of each
// argument in the arg list, not the ParmVarDecl* it maps to.
if (!DIA->getCond()->EvaluateWithSubstitution(
Result, Context, DIA->getParent(), Args, ThisArg))
return false;
return Result.isInt() && Result.getInt().getBoolValue();
});
}
DiagnoseIfAttr *Sema::checkArgIndependentDiagnoseIf(
FunctionDecl *Function, SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal) {
SmallVector<DiagnoseIfAttr *, 4> Errors;
if (!gatherDiagnoseIfAttrs(Function, /*ArgDependent=*/false, Errors,
Nonfatal))
return nullptr;
return checkDiagnoseIfAttrsWith(Errors, Nonfatal, [&](DiagnoseIfAttr *DIA) {
bool Result;
return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
Result;
});
}
void Sema::emitDiagnoseIfDiagnostic(SourceLocation Loc,
const DiagnoseIfAttr *DIA) {
auto Code = DIA->isError() ? diag::err_diagnose_if_succeeded
: diag::warn_diagnose_if_succeeded;
Diag(Loc, Code) << DIA->getMessage();
Diag(DIA->getLocation(), diag::note_from_diagnose_if)
<< DIA->getParent() << DIA->getCond()->getSourceRange();
bool Sema::diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function,
SourceLocation Loc) {
return diagnoseDiagnoseIfAttrsWith(
*this, Function, /*ArgDependent=*/false, Loc,
[&](const DiagnoseIfAttr *DIA) {
bool Result;
return DIA->getCond()->EvaluateAsBooleanCondition(Result, Context) &&
Result;
});
}
/// \brief Add all of the function declarations in the given function set to
@ -6356,8 +6311,8 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
AddMethodCandidate(cast<CXXMethodDecl>(FD), F.getPair(),
cast<CXXMethodDecl>(FD)->getParent(),
Args[0]->getType(), Args[0]->Classify(Context),
Args[0], Args.slice(1), CandidateSet,
SuppressUserConversions, PartialOverloading);
Args.slice(1), CandidateSet, SuppressUserConversions,
PartialOverloading);
else
AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet,
SuppressUserConversions, PartialOverloading);
@ -6369,7 +6324,7 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
FunTmpl, F.getPair(),
cast<CXXRecordDecl>(FunTmpl->getDeclContext()),
ExplicitTemplateArgs, Args[0]->getType(),
Args[0]->Classify(Context), Args[0], Args.slice(1), CandidateSet,
Args[0]->Classify(Context), Args.slice(1), CandidateSet,
SuppressUserConversions, PartialOverloading);
else
AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
@ -6385,7 +6340,6 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
QualType ObjectType,
Expr::Classification ObjectClassification,
Expr *ThisArg,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
@ -6399,15 +6353,13 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
assert(isa<CXXMethodDecl>(TD->getTemplatedDecl()) &&
"Expected a member function template");
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
/*ExplicitArgs*/ nullptr,
ObjectType, ObjectClassification,
ThisArg, Args, CandidateSet,
/*ExplicitArgs*/ nullptr, ObjectType,
ObjectClassification, Args, CandidateSet,
SuppressUserConversions);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, ObjectClassification,
ThisArg, Args,
CandidateSet, SuppressUserConversions);
ObjectType, ObjectClassification, Args, CandidateSet,
SuppressUserConversions);
}
}
@ -6422,7 +6374,7 @@ void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
Expr *ThisArg, ArrayRef<Expr *> Args,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
@ -6544,9 +6496,6 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Method, Args,
/*MissingImplicitThis=*/!ThisArg, ThisArg);
}
/// \brief Add a C++ member function template as a candidate to the candidate
@ -6559,7 +6508,6 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
Expr *ThisArg,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
@ -6613,9 +6561,9 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
assert(isa<CXXMethodDecl>(Specialization) &&
"Specialization is not a member function?");
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, ObjectClassification,
/*ThisArg=*/ThisArg, Args, CandidateSet,
SuppressUserConversions, PartialOverloading, Conversions);
ActingContext, ObjectType, ObjectClassification, Args,
CandidateSet, SuppressUserConversions, PartialOverloading,
Conversions);
}
/// \brief Add a C++ function template specialization as a candidate
@ -6942,8 +6890,6 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, None, false, From);
}
/// \brief Adds a conversion function template specialization
@ -7096,8 +7042,6 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
Candidate.DeductionFailure.Data = FailedAttr;
return;
}
initDiagnoseIfComplaint(*this, CandidateSet, Candidate, Conversion, None);
}
/// \brief Add overload candidates for overloaded operators that are
@ -7146,7 +7090,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
Oper != OperEnd;
++Oper)
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
Args[0]->Classify(Context), Args[0], Args.slice(1),
Args[0]->Classify(Context), Args.slice(1),
CandidateSet, /*SuppressUserConversions=*/false);
}
}
@ -9178,17 +9122,6 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations(
}
}
static bool isCandidateUnavailableDueToDiagnoseIf(const OverloadCandidate &OC) {
ArrayRef<DiagnoseIfAttr *> Info = OC.getDiagnoseIfInfo();
if (!Info.empty() && Info[0]->isError())
return true;
assert(llvm::all_of(Info,
[](const DiagnoseIfAttr *A) { return !A->isError(); }) &&
"DiagnoseIf info shouldn't have mixed warnings and errors.");
return false;
}
/// \brief Computes the best viable function (C++ 13.3.3)
/// within an overload candidate set.
///
@ -9267,19 +9200,13 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Best is the best viable function.
if (Best->Function &&
(Best->Function->isDeleted() ||
S.isFunctionConsideredUnavailable(Best->Function) ||
isCandidateUnavailableDueToDiagnoseIf(*Best)))
S.isFunctionConsideredUnavailable(Best->Function)))
return OR_Deleted;
if (!EquivalentCands.empty())
S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function,
EquivalentCands);
for (const auto *W : Best->getDiagnoseIfInfo()) {
assert(W->isWarning() && "Errors should've been caught earlier!");
S.emitDiagnoseIfDiagnostic(Loc, W);
}
return OR_Success;
}
@ -10162,14 +10089,6 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
if (isCandidateUnavailableDueToDiagnoseIf(*Cand)) {
auto *A = Cand->DiagnoseIfInfo.get<DiagnoseIfAttr *>();
assert(A->isError() && "Non-error diagnose_if disables a candidate?");
S.Diag(Cand->Function->getLocation(),
diag::note_ovl_candidate_disabled_by_function_cond_attr)
<< A->getCond()->getSourceRange() << A->getMessage();
return;
}
// We don't really have anything else to say about viable candidates.
S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
@ -12113,6 +12032,10 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
return ExprError();
if (CheckFunctionCall(FnDecl, TheCall,
FnDecl->getType()->castAs<FunctionProtoType>()))
return ExprError();
return MaybeBindToTemporary(TheCall);
} else {
// We matched a built-in operator. Convert the arguments, then
@ -12343,16 +12266,20 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return ExprError();
ArrayRef<const Expr *> ArgsArray(Args, 2);
const Expr *ImplicitThis = nullptr;
// Cut off the implicit 'this'.
if (isa<CXXMethodDecl>(FnDecl))
if (isa<CXXMethodDecl>(FnDecl)) {
ImplicitThis = ArgsArray[0];
ArgsArray = ArgsArray.slice(1);
}
// Check for a self move.
if (Op == OO_Equal)
DiagnoseSelfMove(Args[0], Args[1], OpLoc);
checkCall(FnDecl, nullptr, ArgsArray, isa<CXXMethodDecl>(FnDecl), OpLoc,
TheCall->getSourceRange(), VariadicDoesNotApply);
checkCall(FnDecl, nullptr, ImplicitThis, ArgsArray,
isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
VariadicDoesNotApply);
return MaybeBindToTemporary(TheCall);
} else {
@ -12561,6 +12488,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
return ExprError();
if (CheckFunctionCall(Method, TheCall,
Method->getType()->castAs<FunctionProtoType>()))
return ExprError();
return MaybeBindToTemporary(TheCall);
} else {
// We matched a built-in operator. Convert the arguments, then
@ -12727,16 +12658,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
TemplateArgs = &TemplateArgsBuffer;
}
// Poor-programmer's Lazy<Expr *>; isImplicitAccess requires stripping
// parens/casts, which would be nice to avoid potentially doing multiple
// times.
llvm::Optional<Expr *> UnresolvedBase;
auto GetUnresolvedBase = [&] {
if (!UnresolvedBase.hasValue())
UnresolvedBase =
UnresExpr->isImplicitAccess() ? nullptr : UnresExpr->getBase();
return *UnresolvedBase;
};
for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(),
E = UnresExpr->decls_end(); I != E; ++I) {
@ -12757,14 +12678,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
continue;
AddMethodCandidate(Method, I.getPair(), ActingDC, ObjectType,
ObjectClassification,
/*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet,
ObjectClassification, Args, CandidateSet,
/*SuppressUserConversions=*/false);
} else {
AddMethodTemplateCandidate(
cast<FunctionTemplateDecl>(Func), I.getPair(), ActingDC,
TemplateArgs, ObjectType, ObjectClassification,
/*ThisArg=*/GetUnresolvedBase(), Args, CandidateSet,
TemplateArgs, ObjectType, ObjectClassification, Args, CandidateSet,
/*SuppressUsedConversions=*/false);
}
}
@ -12882,16 +12801,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
return ExprError();
}
SmallVector<DiagnoseIfAttr *, 4> Nonfatal;
if (const DiagnoseIfAttr *Attr = checkArgDependentDiagnoseIf(
Method, Args, Nonfatal, false, MemE->getBase())) {
emitDiagnoseIfDiagnostic(MemE->getMemberLoc(), Attr);
return ExprError();
}
for (const auto *Attr : Nonfatal)
emitDiagnoseIfDiagnostic(MemE->getMemberLoc(), Attr);
}
if ((isa<CXXConstructorDecl>(CurContext) ||
@ -12970,9 +12879,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Object.get()->getType(),
Object.get()->Classify(Context),
Object.get(), Args, CandidateSet,
/*SuppressUserConversions=*/ false);
Object.get()->Classify(Context), Args, CandidateSet,
/*SuppressUserConversions=*/false);
}
// C++ [over.call.object]p2:
@ -13247,8 +13155,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end();
Oper != OperEnd; ++Oper) {
AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context),
Base, None, CandidateSet,
/*SuppressUserConversions=*/false);
None, CandidateSet, /*SuppressUserConversions=*/false);
}
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@ -13322,7 +13229,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
Base, ResultTy, VK, OpLoc, false);
if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
return ExprError();
return ExprError();
if (CheckFunctionCall(Method, TheCall,
Method->getType()->castAs<FunctionProtoType>()))
return ExprError();
return MaybeBindToTemporary(TheCall);
}

View File

@ -4996,8 +4996,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
NamedDecl *Result = nullptr;
// FIXME: If the name is a dependent name, this lookup won't necessarily
// find it. Does that ever matter?
if (D->getDeclName()) {
DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName());
if (auto Name = D->getDeclName()) {
DeclarationNameInfo NameInfo(Name, D->getLocation());
Name = SubstDeclarationNameInfo(NameInfo, TemplateArgs).getName();
if (!Name)
return nullptr;
DeclContext::lookup_result Found = ParentDC->lookup(Name);
Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
} else {
// Since we don't have a name for the entity we're looking for,

View File

@ -8818,12 +8818,18 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) {
// base (and therefore couldn't do the check) and a
// nested-name-qualifier (and therefore could do the lookup).
NamedDecl *FirstQualifierInScope = nullptr;
DeclarationNameInfo MemberNameInfo = E->getMemberNameInfo();
if (MemberNameInfo.getName()) {
MemberNameInfo = getDerived().TransformDeclarationNameInfo(MemberNameInfo);
if (!MemberNameInfo.getName())
return ExprError();
}
return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc,
E->isArrow(),
QualifierLoc,
TemplateKWLoc,
E->getMemberNameInfo(),
MemberNameInfo,
Member,
FoundDecl,
(E->hasExplicitTemplateArgs()

View File

@ -45,3 +45,12 @@ void __cdecl static_baz() {}
void static_qux() {}
// GCABI-LABEL: define void @_Z10static_quxv
// MSABI: define void @"\01?static_qux@@YAXXZ"
namespace PR31656 {
template <int I>
void __cdecl callee(int args[I]);
// GCABI-LABEL: declare void @_ZN7PR316566calleeILi1EEEvPi(
// MSABI: declare void @"\01??$callee@$00@PR31656@@YAXQAH@Z"(
void caller() { callee<1>(0); }
}

View File

@ -0,0 +1,28 @@
// RUN: %clang_cc1 -Wno-objc-root-class -fblocks -o /dev/null -triple x86_64-- -emit-llvm %s
// REQUIRES: asserts
// Verify there is no assertion.
// rdar://30111891
typedef unsigned long long uint64_t;
typedef enum AnEnum : uint64_t AnEnum;
enum AnEnum: uint64_t {
AnEnumA
};
typedef void (^BlockType)();
@interface MyClass
@end
@implementation MyClass
- (void)_doStuff {
struct {
int identifier;
AnEnum type;
BlockType handler;
} var = {
"hello",
AnEnumA,
((void *)0)
};
}
@end

View File

@ -180,3 +180,14 @@ const char g14[] = @encode(__typeof__(*test_id));
// CHECK: @g15 = constant [2 x i8] c":\00"
const char g15[] = @encode(SEL);
typedef typeof(sizeof(int)) size_t;
size_t strlen(const char *s);
// CHECK-LABEL: @test_strlen(
// CHECK: %[[i:.*]] = alloca i32
// CHECK: store i32 1, i32* %[[i]]
void test_strlen() {
const char array[] = @encode(int);
int i = strlen(array);
}

View File

@ -0,0 +1,11 @@
#pragma GCC system_header
inline int system_header_func(int x)
__attribute__((diagnose_if(x == x, "system header warning", "warning"))) // expected-note {{from 'diagnose_if' attribute}}
{
return 0;
}
void test_system_header() {
system_header_func(0); // expected-warning {{system header warning}}
}

View File

@ -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}}
}
@ -150,3 +150,6 @@ void alwaysWarnWithArg(int a) _diagnose_if(1 || a, "alwaysWarn", "warning"); //
void runAlwaysWarnWithArg(int a) {
alwaysWarnWithArg(a); // expected-warning{{alwaysWarn}}
}
// Test that diagnose_if warnings generated in system headers are not ignored.
#include "Inputs/diagnose-if-warn-system-header.h"

View File

@ -431,3 +431,23 @@ class Invalid {
// The constructor definition should not have errors
Invalid::~Invalid() {}
namespace PR30361 {
template <typename T>
struct C1 {
~C1() {}
operator C1<T>* () { return nullptr; }
void foo1();
};
template<typename T>
void C1<T>::foo1() {
C1::operator C1<T>*();
C1::~C1();
}
void foo1() {
C1<int> x;
x.foo1();
}
}

View File

@ -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}}
}
struct PostInc {
void operator++(int i) _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
_diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
};
void runPostInc() {
PostInc{}++;
PostInc{}.operator++(1); // expected-warning{{oh no}}
PostInc{}.operator++(2); // expected-error{{oh no}}
}
}
@ -439,22 +478,192 @@ struct Foo {
int I;
constexpr Foo(int I): I(I) {}
constexpr const Foo &operator=(const Foo &) const // expected-note 2{{disabled: oh no}}
_diagnose_if(I, "oh no", "error") {
constexpr const Foo &operator=(const Foo &) const
_diagnose_if(I, "oh no", "error") { // expected-note{{from 'diagnose_if'}}
return *this;
}
constexpr const Foo &operator=(const Foo &&) const // expected-note{{disabled: oh no}} expected-note{{no known conversion}}
_diagnose_if(I, "oh no", "error") {
constexpr const Foo &operator=(const Foo &&) const
_diagnose_if(I, "oh no", "error") { // expected-note{{from 'diagnose_if'}}
return *this;
}
};
struct Bar {
int I;
constexpr Bar(int I) _diagnose_if(I == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
_diagnose_if(I == 2, "oh no", "error"): I(I) {} // expected-note{{from 'diagnose_if'}}
};
void run() {
constexpr Foo F{0};
constexpr Foo F2{1};
F2 = F; // expected-error{{selected unavailable operator}}
F2 = Foo{2}; // expected-error{{selected unavailable operator}}
F2 = F; // expected-error{{oh no}}
F2 = Foo{2}; // expected-error{{oh no}}
Bar{0};
Bar{1}; // expected-warning{{oh no}}
Bar{2}; // expected-error{{oh no}}
}
}
namespace ref_init {
struct Bar {};
struct Baz {};
struct Foo {
int i;
constexpr Foo(int i): i(i) {}
operator const Bar &() const _diagnose_if(i, "oh no", "warning"); // expected-note{{from 'diagnose_if'}}
operator const Baz &() const _diagnose_if(i, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
};
void fooBar(const Bar &b);
void fooBaz(const Baz &b);
void run() {
fooBar(Foo{0});
fooBar(Foo{1}); // expected-warning{{oh no}}
fooBaz(Foo{0});
fooBaz(Foo{1}); // expected-error{{oh no}}
}
}
namespace udl {
void operator""_fn(char c)_diagnose_if(c == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
_diagnose_if(c == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
void run() {
'\0'_fn;
'\1'_fn; // expected-warning{{oh no}}
'\2'_fn; // expected-error{{oh no}}
}
}
namespace PR31638 {
struct String {
String(char const* __s) _diagnose_if(__s == nullptr, "oh no ptr", "warning"); // expected-note{{from 'diagnose_if'}}
String(int __s) _diagnose_if(__s != 0, "oh no int", "warning"); // expected-note{{from 'diagnose_if'}}
};
void run() {
String s(nullptr); // expected-warning{{oh no ptr}}
String ss(42); // expected-warning{{oh no int}}
}
}
namespace PR31639 {
struct Foo {
Foo(int I) __attribute__((diagnose_if(I, "oh no", "error"))); // expected-note{{from 'diagnose_if'}}
};
void bar() { Foo f(1); } // expected-error{{oh no}}
}
namespace user_defined_conversion {
struct Foo {
int i;
constexpr Foo(int i): i(i) {}
operator size_t() const _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
_diagnose_if(i == 2, "oh no", "error"); // expected-note{{from 'diagnose_if'}}
};
void run() {
// `new T[N]`, where N is implicitly convertible to size_t, calls
// PerformImplicitConversion directly. This lets us test the diagnostic logic
// in PerformImplicitConversion.
new int[Foo{0}];
new int[Foo{1}]; // expected-warning{{oh no}}
new int[Foo{2}]; // expected-error{{oh no}}
}
}
namespace std {
template <typename T>
struct initializer_list {
const T *ptr;
size_t elems;
constexpr size_t size() const { return elems; }
};
}
namespace initializer_lists {
struct Foo {
Foo(std::initializer_list<int> l)
_diagnose_if(l.size() == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
_diagnose_if(l.size() == 2, "oh no", "error") {} // expected-note{{from 'diagnose_if'}}
};
void run() {
Foo{std::initializer_list<int>{}};
Foo{std::initializer_list<int>{1}}; // expected-warning{{oh no}}
Foo{std::initializer_list<int>{1, 2}}; // expected-error{{oh no}}
Foo{std::initializer_list<int>{1, 2, 3}};
}
}
namespace range_for_loop {
namespace adl {
struct Foo {
int i;
constexpr Foo(int i): i(i) {}
};
void **begin(const Foo &f) _diagnose_if(f.i, "oh no", "warning");
void **end(const Foo &f) _diagnose_if(f.i, "oh no", "warning");
struct Bar {
int i;
constexpr Bar(int i): i(i) {}
};
void **begin(const Bar &b) _diagnose_if(b.i, "oh no", "error");
void **end(const Bar &b) _diagnose_if(b.i, "oh no", "error");
}
void run() {
for (void *p : adl::Foo(0)) {}
// FIXME: This should emit diagnostics. It seems that our constexpr
// evaluator isn't able to evaluate `adl::Foo(1)` as a constant, though.
for (void *p : adl::Foo(1)) {}
for (void *p : adl::Bar(0)) {}
// FIXME: Same thing.
for (void *p : adl::Bar(1)) {}
}
}
namespace operator_new {
struct Foo {
int j;
static void *operator new(size_t i) _diagnose_if(i, "oh no", "warning");
};
struct Bar {
int j;
static void *operator new(size_t i) _diagnose_if(!i, "oh no", "warning");
};
void run() {
// FIXME: This should emit a diagnostic.
new Foo();
// This is here because we sometimes pass a dummy argument `operator new`. We
// should ignore this, rather than complaining about it.
new Bar();
}
}
namespace contextual_implicit_conv {
struct Foo {
int i;
constexpr Foo(int i): i(i) {}
constexpr operator int() const _diagnose_if(i == 1, "oh no", "warning") // expected-note{{from 'diagnose_if'}}
_diagnose_if(i == 2, "oh no", "error") { // expected-note{{from 'diagnose_if'}}
return i;
}
};
void run() {
switch (constexpr Foo i = 0) { default: break; }
switch (constexpr Foo i = 1) { default: break; } // expected-warning{{oh no}}
switch (constexpr Foo i = 2) { default: break; } // expected-error{{oh no}}
}
}