diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-02-01 21:35:00 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-02-01 21:35:00 +0000 |
commit | 123063377428540752bad91c7fbd536a762e31bd (patch) | |
tree | f131a156bf0b3912bc02dd7adaf4898c01c8a119 | |
parent | d1b6c770bea9b3da66c6c1eb9a7c483ed7e55c1e (diff) |
Notes
-rw-r--r-- | include/clang/AST/Type.h | 14 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | include/clang/Sema/Overload.h | 32 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 51 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 34 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 285 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 8 | ||||
-rw-r--r-- | test/CodeGenCXX/microsoft-abi-default-cc.cpp | 9 | ||||
-rw-r--r-- | test/CodeGenObjC/block-ptr-type-crash.m | 28 | ||||
-rw-r--r-- | test/CodeGenObjC/encode-test.m | 11 | ||||
-rw-r--r-- | test/Sema/Inputs/diagnose-if-warn-system-header.h | 11 | ||||
-rw-r--r-- | test/Sema/diagnose_if.c | 9 | ||||
-rw-r--r-- | test/SemaCXX/destructor.cpp | 20 | ||||
-rw-r--r-- | test/SemaCXX/diagnose_if.cpp | 313 |
20 files changed, 528 insertions, 346 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 744a408e5796..a50e054f9b28 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -3827,13 +3827,13 @@ private: 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; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2d74eecc276e..c9343519e38b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index 88fdc991f394..5220d9873022 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -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) { diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c180a8ea3ee1..63d078498fe4 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2532,14 +2532,14 @@ public: void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, - Expr *ThisArg, ArrayRef<Expr *> Args, + ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, - Expr *ThisArg, ArrayRef<Expr *> Args, + ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, @@ -2550,7 +2550,6 @@ public: TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, - Expr *ThisArg, ArrayRef<Expr *> Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, @@ -2624,37 +2623,27 @@ public: EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, bool MissingImplicitThis = false); - /// Check the diagnose_if attributes on the given function. Returns the - /// first succesful fatal attribute, or null if calling Function(Args) isn't - /// an error. + /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any + /// non-ArgDependent DiagnoseIfAttrs. /// - /// This only considers ArgDependent DiagnoseIfAttrs. + /// Argument-dependent diagnose_if attributes should be checked each time a + /// function is used as a direct callee of a function call. /// - /// This will populate Nonfatal with all non-error DiagnoseIfAttrs that - /// succeed. If this function returns non-null, the contents of Nonfatal are - /// unspecified. - DiagnoseIfAttr * - checkArgDependentDiagnoseIf(FunctionDecl *Function, ArrayRef<Expr *> Args, - SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal, - bool MissingImplicitThis = false, - Expr *ThisArg = nullptr); + /// Returns true if any errors were emitted. + bool diagnoseArgDependentDiagnoseIfAttrs(const FunctionDecl *Function, + const Expr *ThisArg, + ArrayRef<const Expr *> Args, + SourceLocation Loc); - /// Check the diagnose_if expressions on the given function. Returns the - /// first succesful fatal attribute, or null if using Function isn't - /// an error. + /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any + /// ArgDependent DiagnoseIfAttrs. /// - /// This ignores all ArgDependent DiagnoseIfAttrs. + /// Argument-independent diagnose_if attributes should be checked on every use + /// of a function. /// - /// This will populate Nonfatal with all non-error DiagnoseIfAttrs that - /// succeed. If this function returns non-null, the contents of Nonfatal are - /// unspecified. - DiagnoseIfAttr * - checkArgIndependentDiagnoseIf(FunctionDecl *Function, - SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal); - - /// Emits the diagnostic contained in the given DiagnoseIfAttr at Loc. Also - /// emits a note about the location of said attribute. - void emitDiagnoseIfDiagnostic(SourceLocation Loc, const DiagnoseIfAttr *DIA); + /// Returns true if any errors were emitted. + bool diagnoseArgIndependentDiagnoseIfAttrs(const FunctionDecl *Function, + SourceLocation Loc); /// Returns whether the given function's address can be taken or not, /// optionally emitting a diagnostic if the address can't be taken. @@ -9914,8 +9903,8 @@ private: SourceLocation Loc); void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, - ArrayRef<const Expr *> Args, bool IsMemberFunction, - SourceLocation Loc, SourceRange Range, + const Expr *ThisArg, ArrayRef<const Expr *> Args, + bool IsMemberFunction, SourceLocation Loc, SourceRange Range, VariadicCallType CallType); bool CheckObjCString(Expr *Arg); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 5fab58a5af95..6a6baf96ad37 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index b95b4fff5734..adb40c8c0d47 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -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); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 49208e20a49d..3aedb2a8c9bb 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e1e1f0283629..0077d6c539c3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index b2fb33f53432..3de677e37ba2 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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; } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 883e2ae264e9..38a7b8c127cc 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -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, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index c66fe7678d8c..f976b76727f5 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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); - } +template <typename CheckFn> +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); + } - return !Errors.empty() || !Nonfatal.empty(); -} + // 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(); }); -template <typename CheckFn> -static DiagnoseIfAttr * -checkDiagnoseIfAttrsWith(const SmallVectorImpl<DiagnoseIfAttr *> &Errors, - SmallVectorImpl<DiagnoseIfAttr *> &Nonfatal, - CheckFn &&IsSuccessful) { // 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; - - llvm::erase_if(Nonfatal, [&](DiagnoseIfAttr *A) { return !IsSuccessful(A); }); - return nullptr; -} - -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; + 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; + } - SFINAETrap Trap(*this); - SmallVector<Expr *, 16> ConvertedArgs; - Expr *ConvertedThis; - if (!convertArgsForAvailabilityChecks(*this, Function, ThisArg, Args, Trap, - MissingImplicitThis, ConvertedThis, - ConvertedArgs)) - 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 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(); - }); + return false; } -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; - }); +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(); + }); } -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); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 48d8b94af153..200775756d3a 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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, diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index c2aa3fef67c8..4388ad34e21b 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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() diff --git a/test/CodeGenCXX/microsoft-abi-default-cc.cpp b/test/CodeGenCXX/microsoft-abi-default-cc.cpp index e3ca39221e88..6259a53dbf39 100644 --- a/test/CodeGenCXX/microsoft-abi-default-cc.cpp +++ b/test/CodeGenCXX/microsoft-abi-default-cc.cpp @@ -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); } +} diff --git a/test/CodeGenObjC/block-ptr-type-crash.m b/test/CodeGenObjC/block-ptr-type-crash.m new file mode 100644 index 000000000000..385d64585897 --- /dev/null +++ b/test/CodeGenObjC/block-ptr-type-crash.m @@ -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 diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m index 7f0e76fc3ffd..a1f88e05250a 100644 --- a/test/CodeGenObjC/encode-test.m +++ b/test/CodeGenObjC/encode-test.m @@ -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); +} diff --git a/test/Sema/Inputs/diagnose-if-warn-system-header.h b/test/Sema/Inputs/diagnose-if-warn-system-header.h new file mode 100644 index 000000000000..753c69d4b532 --- /dev/null +++ b/test/Sema/Inputs/diagnose-if-warn-system-header.h @@ -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}} +} diff --git a/test/Sema/diagnose_if.c b/test/Sema/diagnose_if.c index 219e393bc0cc..27689f49b431 100644 --- a/test/Sema/diagnose_if.c +++ b/test/Sema/diagnose_if.c @@ -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" diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp index fe1dde5771ac..49cdc50f3c13 100644 --- a/test/SemaCXX/destructor.cpp +++ b/test/SemaCXX/destructor.cpp @@ -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(); +} +} diff --git a/test/SemaCXX/diagnose_if.cpp b/test/SemaCXX/diagnose_if.cpp index f97b79d03529..02b3620e7692 100644 --- a/test/SemaCXX/diagnose_if.cpp +++ b/test/SemaCXX/diagnose_if.cpp @@ -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}} } } |