Vendor import of clang release_40 branch r293807:
https://llvm.org/svn/llvm-project/cfe/branches/release_40@293807
This commit is contained in:
parent
d1b6c770be
commit
1230633774
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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<
|
||||
|
@ -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 @@ 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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
|
@ -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); }
|
||||
}
|
||||
|
28
test/CodeGenObjC/block-ptr-type-crash.m
Normal file
28
test/CodeGenObjC/block-ptr-type-crash.m
Normal 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
|
@ -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);
|
||||
}
|
||||
|
11
test/Sema/Inputs/diagnose-if-warn-system-header.h
Normal file
11
test/Sema/Inputs/diagnose-if-warn-system-header.h
Normal 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}}
|
||||
}
|
@ -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"
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user