From: Diego Novillo Date: Thu, 14 May 2015 20:57:48 +0000 (+0000) Subject: Revert "Detect uses of mismatching forms of 'new' and 'delete'" X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8863f9bb8b50e25a6229ed194dc248c5d772c360;p=clang Revert "Detect uses of mismatching forms of 'new' and 'delete'" This reverts commit 742dc9b6c9686ab52860b7da39c3a126d8a97fbc. This is generating multiple segfaults in our internal builds. Test case coming up shortly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@237391 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0df7f627bc..b600ec1766 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5510,12 +5510,7 @@ def err_delete_explicit_conversion : Error< "conversion function">; def note_delete_conversion : Note<"conversion to pointer type %0">; def warn_delete_array_type : Warning< - "'delete' applied to a pointer-to-array type %0 treated as 'delete[]'">; -def warn_mismatched_delete_new : Warning< - "'delete%select{|[]}0' applied to a pointer that was allocated with " - "'new%select{[]|}0'; did you mean 'delete%select{[]|}0'?">, - InGroup>; -def note_allocated_here : Note<"allocated with 'new%select{[]|}0' here">; + "'delete' applied to a pointer-to-array type %0 treated as delete[]">; def err_no_suitable_delete_member_function_found : Error< "no suitable member %0 in %1">; def err_ambiguous_suitable_delete_member_function_found : Error< diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index ef3d2dbff1..de4672f1af 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -27,7 +27,6 @@ template class SmallSetVector; namespace clang { class CXXConstructorDecl; -class CXXDeleteExpr; class CXXRecordDecl; class DeclaratorDecl; class LookupResult; @@ -80,9 +79,6 @@ public: virtual void ReadUndefinedButUsed( llvm::DenseMap &Undefined); - virtual void ReadMismatchingDeleteExpressions(llvm::MapVector< - FieldDecl *, llvm::SmallVector, 4>> &); - /// \brief Do last resort, unqualified lookup on a LookupResult that /// Sema cannot find. /// diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h index af7083a82d..16646ba4ad 100644 --- a/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/include/clang/Sema/MultiplexExternalSemaSource.h @@ -230,10 +230,6 @@ public: void ReadUndefinedButUsed( llvm::DenseMap &Undefined) override; - void ReadMismatchingDeleteExpressions(llvm::MapVector< - FieldDecl *, llvm::SmallVector, 4>> & - Exprs) override; - /// \brief Do last resort, unqualified lookup on a LookupResult that /// Sema cannot find. /// diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index cf7b316b08..3bc1b4d7d3 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -78,7 +78,6 @@ namespace clang { typedef SmallVector CXXCastPath; class CXXConstructorDecl; class CXXConversionDecl; - class CXXDeleteExpr; class CXXDestructorDecl; class CXXFieldCollector; class CXXMemberCallExpr; @@ -403,15 +402,6 @@ public: llvm::SmallSetVector UnusedLocalTypedefNameCandidates; - /// \brief Delete-expressions to be analyzed at the end of translation unit - /// - /// This list contains class members, and locations of delete-expressions - /// that could not be proven as to whether they mismatch with new-expression - /// used in initializer of the field. - typedef std::pair DeleteExprLoc; - typedef llvm::SmallVector DeleteLocs; - llvm::MapVector DeleteExprs; - typedef llvm::SmallPtrSet RecordDeclSetTy; /// PureVirtualClassDiagSet - a set of class declarations which we have @@ -896,11 +886,6 @@ public: void getUndefinedButUsed( SmallVectorImpl > &Undefined); - /// Retrieves list of suspicious delete-expressions that will be checked at - /// the end of translation unit. - const llvm::MapVector & - getMismatchingDeleteExpressions() const; - typedef std::pair GlobalMethods; typedef llvm::DenseMap GlobalMethodPool; @@ -8654,9 +8639,6 @@ private: /// attempts to add itself into the container void CheckObjCCircularContainer(ObjCMessageExpr *Message); - void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); - void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, - bool DeleteWasArrayForm); public: /// \brief Register a magic integral constant to be used as a type tag. void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index e0f01c8a35..511e73b96f 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -561,9 +561,6 @@ namespace clang { /// \brief Record code for the table of offsets to CXXCtorInitializers /// lists. CXX_CTOR_INITIALIZERS_OFFSETS = 53, - - /// \brief Delete expressions that will be analyzed later. - DELETE_EXPRS_TO_ANALYZE = 54 }; /// \brief Record types used within a source manager block. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 713f4c952a..9f9b45e8a5 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -756,9 +756,6 @@ private: /// SourceLocation of a matching ODR-use. SmallVector UndefinedButUsed; - /// \brief Delete expressions to analyze at the end of translation unit. - SmallVector DelayedDeleteExprs; - // \brief A list of late parsed template function data. SmallVector LateParsedTemplates; @@ -1739,10 +1736,6 @@ public: void ReadUndefinedButUsed( llvm::DenseMap &Undefined) override; - void ReadMismatchingDeleteExpressions(llvm::MapVector< - FieldDecl *, llvm::SmallVector, 4>> & - Exprs); - void ReadTentativeDefinitions( SmallVectorImpl &TentativeDefs) override; diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp index 9ecb5a7fef..51a12746fd 100644 --- a/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/lib/Sema/MultiplexExternalSemaSource.cpp @@ -212,15 +212,7 @@ void MultiplexExternalSemaSource::ReadUndefinedButUsed( for(size_t i = 0; i < Sources.size(); ++i) Sources[i]->ReadUndefinedButUsed(Undefined); } - -void MultiplexExternalSemaSource::ReadMismatchingDeleteExpressions( - llvm::MapVector, 4>> & - Exprs) { - for (auto &Source : Sources) - Source->ReadMismatchingDeleteExpressions(Exprs); -} - + bool MultiplexExternalSemaSource::LookupUnqualified(LookupResult &R, Scope *S){ for(size_t i = 0; i < Sources.size(); ++i) Sources[i]->LookupUnqualified(R, S); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index dea01bab07..6825dfa41f 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -860,17 +860,6 @@ void Sema::ActOnEndOfTranslationUnit() { } } - if (!Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation())) { - if (ExternalSource) - ExternalSource->ReadMismatchingDeleteExpressions(DeleteExprs); - for (const auto &DeletedFieldInfo : DeleteExprs) { - for (const auto &DeleteExprLoc : DeletedFieldInfo.second) { - AnalyzeDeleteExprMismatch(DeletedFieldInfo.first, DeleteExprLoc.first, - DeleteExprLoc.second); - } - } - } - // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug. @@ -1230,9 +1219,6 @@ void ExternalSemaSource::ReadUndefinedButUsed( llvm::DenseMap &Undefined) { } -void ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector< - FieldDecl *, llvm::SmallVector, 4>> &) {} - void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const { SourceLocation Loc = this->Loc; if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); @@ -1481,8 +1467,3 @@ CapturedRegionScopeInfo *Sema::getCurCapturedRegion() { return dyn_cast(FunctionScopes.back()); } - -const llvm::MapVector & -Sema::getMismatchingDeleteExpressions() const { - return DeleteExprs; -} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 12f06360a1..b853eaefbe 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2339,261 +2339,6 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, return false; } -namespace { -/// \brief Checks whether delete-expression, and new-expression used for -/// initializing deletee have the same array form. -class MismatchingNewDeleteDetector { -public: - enum MismatchResult { - /// Indicates that there is no mismatch or a mismatch cannot be proven. - NoMismatch, - /// Indicates that variable is initialized with mismatching form of \a new. - VarInitMismatches, - /// Indicates that member is initialized with mismatching form of \a new. - MemberInitMismatches, - /// Indicates that 1 or more constructors' definitions could not been - /// analyzed, and they will be checked again at the end of translation unit. - AnalyzeLater - }; - - /// \param EndOfTU True, if this is the final analysis at the end of - /// translation unit. False, if this is the initial analysis at the point - /// delete-expression was encountered. - explicit MismatchingNewDeleteDetector(bool EndOfTU) - : IsArrayForm(false), Field(nullptr), EndOfTU(EndOfTU), - HasUndefinedConstructors(false) {} - - /// \brief Checks whether pointee of a delete-expression is initialized with - /// matching form of new-expression. - /// - /// If return value is \c VarInitMismatches or \c MemberInitMismatches at the - /// point where delete-expression is encountered, then a warning will be - /// issued immediately. If return value is \c AnalyzeLater at the point where - /// delete-expression is seen, then member will be analyzed at the end of - /// translation unit. \c AnalyzeLater is returned iff at least one constructor - /// couldn't be analyzed. If at least one constructor initializes the member - /// with matching type of new, the return value is \c NoMismatch. - MismatchResult analyzeDeleteExpr(const CXXDeleteExpr *DE); - /// \brief Analyzes a class member. - /// \param Field Class member to analyze. - /// \param DeleteWasArrayForm Array form-ness of the delete-expression used - /// for deleting the \p Field. - MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm); - /// List of mismatching new-expressions used for initialization of the pointee - llvm::SmallVector NewExprs; - /// Indicates whether delete-expression was in array form. - bool IsArrayForm; - FieldDecl *Field; - -private: - const bool EndOfTU; - /// \brief Indicates that there is at least one constructor without body. - bool HasUndefinedConstructors; - /// \brief Returns \c CXXNewExpr from given initialization expression. - /// \param E Expression used for initializing pointee in delete-expression. - /// \param E can be a single-element \c InitListExpr consisting of - /// \param E new-expression. - const CXXNewExpr *getNewExprFromInitListOrExpr(const Expr *E); - /// \brief Returns whether member is initialized with mismatching form of - /// \c new either by the member initializer or in-class initialization. - /// - /// If bodies of all constructors are not visible at the end of translation - /// unit or at least one constructor initializes member with the matching - /// form of \c new, mismatch cannot be proven, and this function will return - /// \c NoMismatch. - MismatchResult analyzeMemberExpr(const MemberExpr *ME); - /// \brief Returns whether variable is initialized with mismatching form of - /// \c new. - /// - /// If variable is initialized with matching form of \c new or variable is not - /// initialized with a \c new expression, this function will return true. - /// If variable is initialized with mismatching form of \c new, returns false. - /// \param D Variable to analyze. - bool hasMatchingVarInit(const DeclRefExpr *D); - /// \brief Checks whether the constructor initializes pointee with mismatching - /// form of \c new. - /// - /// Returns true, if member is initialized with matching form of \c new in - /// member initializer list. Returns false, if member is initialized with the - /// matching form of \c new in this constructor's initializer or given - /// constructor isn't defined at the point where delete-expression is seen, or - /// member isn't initialized by the constructor. - bool hasMatchingNewInCtor(const CXXConstructorDecl *CD); - /// \brief Checks whether member is initialized with matching form of - /// \c new in member initializer list. - bool hasMatchingNewInCtorInit(const CXXCtorInitializer *CI); - /// Checks whether member is initialized with mismatching form of \c new by - /// in-class initializer. - MismatchResult analyzeInClassInitializer(); -}; -} - -MismatchingNewDeleteDetector::MismatchResult -MismatchingNewDeleteDetector::analyzeDeleteExpr(const CXXDeleteExpr *DE) { - NewExprs.clear(); - assert(DE && "Expected delete-expression"); - IsArrayForm = DE->isArrayForm(); - const Expr *E = DE->getArgument()->IgnoreParenImpCasts(); - if (const MemberExpr *ME = dyn_cast(E)) { - return analyzeMemberExpr(ME); - } else if (const DeclRefExpr *D = dyn_cast(E)) { - if (!hasMatchingVarInit(D)) - return VarInitMismatches; - } - return NoMismatch; -} - -const CXXNewExpr * -MismatchingNewDeleteDetector::getNewExprFromInitListOrExpr(const Expr *E) { - assert(E != nullptr && "Expected a valid initializer expression"); - E = E->IgnoreParenImpCasts(); - if (const InitListExpr *ILE = dyn_cast(E)) { - if (ILE->getNumInits() == 1) - E = dyn_cast(ILE->getInit(0)->IgnoreParenImpCasts()); - } - - return dyn_cast(E); -} - -bool MismatchingNewDeleteDetector::hasMatchingNewInCtorInit( - const CXXCtorInitializer *CI) { - const CXXNewExpr *NE = nullptr; - if (Field == CI->getMember() && - (NE = getNewExprFromInitListOrExpr(CI->getInit()))) { - if (NE->isArray() == IsArrayForm) - return true; - else - NewExprs.push_back(NE); - } - return false; -} - -bool MismatchingNewDeleteDetector::hasMatchingNewInCtor( - const CXXConstructorDecl *CD) { - if (CD->isImplicit()) - return false; - const FunctionDecl *Definition = CD; - if (!CD->isThisDeclarationADefinition() && !CD->isDefined(Definition)) { - HasUndefinedConstructors = true; - return EndOfTU; - } - for (const auto *CI : cast(Definition)->inits()) { - if (hasMatchingNewInCtorInit(CI)) - return true; - } - return false; -} - -MismatchingNewDeleteDetector::MismatchResult -MismatchingNewDeleteDetector::analyzeInClassInitializer() { - assert(Field != nullptr && "This should be called only for members"); - if (const CXXNewExpr *NE = - getNewExprFromInitListOrExpr(Field->getInClassInitializer())) { - if (NE->isArray() != IsArrayForm) { - NewExprs.push_back(NE); - return MemberInitMismatches; - } - } - return NoMismatch; -} - -MismatchingNewDeleteDetector::MismatchResult -MismatchingNewDeleteDetector::analyzeField(FieldDecl *Field, - bool DeleteWasArrayForm) { - assert(Field != nullptr && "Analysis requires a valid class member."); - this->Field = Field; - IsArrayForm = DeleteWasArrayForm; - const CXXRecordDecl *RD = cast(Field->getParent()); - for (const auto *CD : RD->ctors()) { - if (hasMatchingNewInCtor(CD)) - return NoMismatch; - } - if (HasUndefinedConstructors) - return EndOfTU ? NoMismatch : AnalyzeLater; - if (!NewExprs.empty()) - return MemberInitMismatches; - return Field->hasInClassInitializer() ? analyzeInClassInitializer() - : NoMismatch; -} - -MismatchingNewDeleteDetector::MismatchResult -MismatchingNewDeleteDetector::analyzeMemberExpr(const MemberExpr *ME) { - assert(ME != nullptr && "Expected a member expression"); - if (FieldDecl *F = dyn_cast(ME->getMemberDecl())) - return analyzeField(F, IsArrayForm); - return NoMismatch; -} - -bool MismatchingNewDeleteDetector::hasMatchingVarInit(const DeclRefExpr *D) { - const CXXNewExpr *NE = nullptr; - if (const VarDecl *VD = dyn_cast(D->getDecl())) { - if (VD->hasInit() && (NE = getNewExprFromInitListOrExpr(VD->getInit())) && - NE->isArray() != IsArrayForm) { - NewExprs.push_back(NE); - } - } - return NewExprs.empty(); -} - -static void -DiagnoseMismatchedNewDelete(Sema &SemaRef, SourceLocation DeleteLoc, - const MismatchingNewDeleteDetector &Detector) { - SourceLocation EndOfDelete = SemaRef.getLocForEndOfToken(DeleteLoc); - FixItHint H; - if (!Detector.IsArrayForm) - H = FixItHint::CreateInsertion(EndOfDelete, "[]"); - else { - SourceLocation RSquare = Lexer::findLocationAfterToken( - DeleteLoc, tok::l_square, SemaRef.getSourceManager(), - SemaRef.getLangOpts(), true); - if (RSquare.isValid()) - H = FixItHint::CreateRemoval(SourceRange(EndOfDelete, RSquare)); - } - SemaRef.Diag(DeleteLoc, diag::warn_mismatched_delete_new) - << Detector.IsArrayForm << H; - - for (const auto *NE : Detector.NewExprs) - SemaRef.Diag(NE->getExprLoc(), diag::note_allocated_here) - << Detector.IsArrayForm; -} - -void Sema::AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE) { - if (Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation())) - return; - MismatchingNewDeleteDetector Detector(/*EndOfTU=*/false); - switch (Detector.analyzeDeleteExpr(DE)) { - case MismatchingNewDeleteDetector::VarInitMismatches: - case MismatchingNewDeleteDetector::MemberInitMismatches: { - DiagnoseMismatchedNewDelete(*this, DE->getLocStart(), Detector); - break; - } - case MismatchingNewDeleteDetector::AnalyzeLater: { - DeleteExprs[Detector.Field].push_back( - std::make_pair(DE->getLocStart(), DE->isArrayForm())); - break; - } - case MismatchingNewDeleteDetector::NoMismatch: - break; - } -} - -void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, - bool DeleteWasArrayForm) { - MismatchingNewDeleteDetector Detector(/*EndOfTU=*/true); - switch (Detector.analyzeField(Field, DeleteWasArrayForm)) { - case MismatchingNewDeleteDetector::VarInitMismatches: - llvm_unreachable("This analysis should have been done for class members."); - case MismatchingNewDeleteDetector::AnalyzeLater: - llvm_unreachable("Analysis cannot be postponed any point beyond end of " - "translation unit."); - case MismatchingNewDeleteDetector::MemberInitMismatches: - DiagnoseMismatchedNewDelete(*this, DeleteLoc, Detector); - break; - case MismatchingNewDeleteDetector::NoMismatch: - break; - } -} - /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or @@ -2709,6 +2454,12 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, } } + // C++ [expr.delete]p2: + // [Note: a pointer to a const type can be the operand of a + // delete-expression; it is not necessary to cast away the constness + // (5.2.11) of the pointer expression before it is used as the operand + // of the delete-expression. ] + if (Pointee->isArrayType() && !ArrayForm) { Diag(StartLoc, diag::warn_delete_array_type) << Type << Ex.get()->getSourceRange() @@ -2783,7 +2534,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, DeleteName); MarkFunctionReferenced(StartLoc, OperatorDelete); - + // Check access and ambiguity of operator delete and destructor. if (PointeeRD) { if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { @@ -2793,11 +2544,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, } } - CXXDeleteExpr *Result = new (Context) CXXDeleteExpr( + return new (Context) CXXDeleteExpr( Context.VoidTy, UseGlobal, ArrayForm, ArrayFormAsWritten, UsualArrayDeleteWantsSize, OperatorDelete, Ex.get(), StartLoc); - AnalyzeDeleteExprMismatch(Result); - return Result; } /// \brief Check the use of the given variable as a C++ condition in an if, diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 0aeb1fffab..c4b4aec24a 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3021,18 +3021,6 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { ReadSourceLocation(F, Record, I).getRawEncoding()); } break; - case DELETE_EXPRS_TO_ANALYZE: - for (unsigned I = 0, N = Record.size(); I != N;) { - DelayedDeleteExprs.push_back(getGlobalDeclID(F, Record[I++])); - const uint64_t Count = Record[I++]; - DelayedDeleteExprs.push_back(Count); - for (uint64_t C = 0; C < Count; ++C) { - DelayedDeleteExprs.push_back(ReadSourceLocation(F, Record, I).getRawEncoding()); - bool IsArrayForm = Record[I++] == 1; - DelayedDeleteExprs.push_back(IsArrayForm); - } - } - break; case IMPORTED_MODULES: { if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) { @@ -7025,21 +7013,6 @@ void ASTReader::ReadUndefinedButUsed( } } -void ASTReader::ReadMismatchingDeleteExpressions(llvm::MapVector< - FieldDecl *, llvm::SmallVector, 4>> & - Exprs) { - for (unsigned Idx = 0, N = DelayedDeleteExprs.size(); Idx != N;) { - FieldDecl *FD = cast(GetDecl(DelayedDeleteExprs[Idx++])); - uint64_t Count = DelayedDeleteExprs[Idx++]; - for (uint64_t C = 0; C < Count; ++C) { - SourceLocation DeleteLoc = - SourceLocation::getFromRawEncoding(DelayedDeleteExprs[Idx++]); - const bool IsArrayForm = DelayedDeleteExprs[Idx++]; - Exprs[FD].push_back(std::make_pair(DeleteLoc, IsArrayForm)); - } - } -} - void ASTReader::ReadTentativeDefinitions( SmallVectorImpl &TentativeDefs) { for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index c1398e26c7..29a88a13d3 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4155,20 +4155,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, AddSourceLocation(I->second, UndefinedButUsed); } - // Build a record containing all delete-expressions that we would like to - // analyze later in AST. - RecordData DeleteExprsToAnalyze; - - for (const auto &DeleteExprsInfo : - SemaRef.getMismatchingDeleteExpressions()) { - AddDeclRef(DeleteExprsInfo.first, DeleteExprsToAnalyze); - DeleteExprsToAnalyze.push_back(DeleteExprsInfo.second.size()); - for (const auto &DeleteLoc : DeleteExprsInfo.second) { - AddSourceLocation(DeleteLoc.first, DeleteExprsToAnalyze); - DeleteExprsToAnalyze.push_back(DeleteLoc.second); - } - } - // Write the control block WriteControlBlock(PP, Context, isysroot, OutputFile); @@ -4438,10 +4424,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, // Write the undefined internal functions and variables, and inline functions. if (!UndefinedButUsed.empty()) Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed); - - if (!DeleteExprsToAnalyze.empty()) - Stream.EmitRecord(DELETE_EXPRS_TO_ANALYZE, DeleteExprsToAnalyze); - + // Write the visible updates to DeclContexts. for (auto *DC : UpdatedDeclContexts) WriteDeclContextVisibleUpdate(DC); diff --git a/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp index 6fab8bb668..fca02aa278 100644 --- a/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp +++ b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp @@ -97,11 +97,9 @@ void testShouldReportDoubleFreeNotMismatched() { free(p); delete globalPtr; // expected-warning {{Attempt to free released memory}} } -int *allocIntArray(unsigned c) { - return new int[c]; -} + void testMismatchedChangePointeeThroughAssignment() { - int *arr = allocIntArray(4); + int *arr = new int[4]; globalPtr = arr; delete arr; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}} -} +} \ No newline at end of file diff --git a/test/Analysis/MismatchedDeallocator-checker-test.mm b/test/Analysis/MismatchedDeallocator-checker-test.mm index 3cc3e18c7c..15815e80bf 100644 --- a/test/Analysis/MismatchedDeallocator-checker-test.mm +++ b/test/Analysis/MismatchedDeallocator-checker-test.mm @@ -95,11 +95,8 @@ void testNew6() { realloc(p, sizeof(long)); // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not realloc()}} } -int *allocInt() { - return new int; -} void testNew7() { - int *p = allocInt(); + int *p = new int; delete[] p; // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not 'delete[]'}} } @@ -108,12 +105,8 @@ void testNew8() { delete[] p; // expected-warning{{Memory allocated by operator new should be deallocated by 'delete', not 'delete[]'}} } -int *allocIntArray(unsigned c) { - return new int[c]; -} - void testNew9() { - int *p = allocIntArray(1); + int *p = new int[1]; delete p; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}} } diff --git a/test/Analysis/MismatchedDeallocator-path-notes.cpp b/test/Analysis/MismatchedDeallocator-path-notes.cpp index af24197f13..686497c4a9 100644 --- a/test/Analysis/MismatchedDeallocator-path-notes.cpp +++ b/test/Analysis/MismatchedDeallocator-path-notes.cpp @@ -3,12 +3,9 @@ // RUN: FileCheck --input-file=%t.plist %s void changePointee(int *p); -int *allocIntArray(unsigned c) { - return new int[c]; // expected-note {{Memory is allocated}} -} void test() { - int *p = allocIntArray(1); // expected-note {{Calling 'allocIntArray'}} - // expected-note@-1 {{Returned allocated memory}} + int *p = new int[1]; + // expected-note@-1 {{Memory is allocated}} changePointee(p); delete p; // expected-warning {{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}} // expected-note@-1 {{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}} @@ -27,124 +24,13 @@ void test() { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col5 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: end -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col12 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col24 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindevent -// CHECK-NEXT: location -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col12 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: ranges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col12 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col27 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: depth0 -// CHECK-NEXT: extended_message -// CHECK-NEXT: Calling 'allocIntArray' -// CHECK-NEXT: message -// CHECK-NEXT: Calling 'allocIntArray' -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindevent -// CHECK-NEXT: location -// CHECK-NEXT: -// CHECK-NEXT: line6 -// CHECK-NEXT: col1 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: depth1 -// CHECK-NEXT: extended_message -// CHECK-NEXT: Entered call from 'test' -// CHECK-NEXT: message -// CHECK-NEXT: Entered call from 'test' -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindcontrol -// CHECK-NEXT: edges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: start -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line6 -// CHECK-NEXT: col1 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line6 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: end -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line7 -// CHECK-NEXT: col3 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line7 -// CHECK-NEXT: col8 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: kindcontrol -// CHECK-NEXT: edges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: start -// CHECK-NEXT: -// CHECK-NEXT: // CHECK-NEXT: line7 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: line7 -// CHECK-NEXT: col8 +// CHECK-NEXT: col5 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: @@ -152,12 +38,12 @@ void test() { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: line7 -// CHECK-NEXT: col10 +// CHECK-NEXT: col12 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: line7 -// CHECK-NEXT: col12 +// CHECK-NEXT: col14 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: @@ -169,7 +55,7 @@ void test() { // CHECK-NEXT: location // CHECK-NEXT: // CHECK-NEXT: line7 -// CHECK-NEXT: col10 +// CHECK-NEXT: col12 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: ranges @@ -177,52 +63,23 @@ void test() { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: line7 -// CHECK-NEXT: col10 +// CHECK-NEXT: col12 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: line7 -// CHECK-NEXT: col19 +// CHECK-NEXT: col21 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: depth1 +// CHECK-NEXT: depth0 // CHECK-NEXT: extended_message // CHECK-NEXT: Memory is allocated // CHECK-NEXT: message // CHECK-NEXT: Memory is allocated // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: kindevent -// CHECK-NEXT: location -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col12 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: ranges -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col12 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col27 -// CHECK-NEXT: file0 -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: -// CHECK-NEXT: depth0 -// CHECK-NEXT: extended_message -// CHECK-NEXT: Returned allocated memory -// CHECK-NEXT: message -// CHECK-NEXT: Returned allocated memory -// CHECK-NEXT: -// CHECK-NEXT: // CHECK-NEXT: kindcontrol // CHECK-NEXT: edges // CHECK-NEXT: @@ -230,25 +87,25 @@ void test() { // CHECK-NEXT: start // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line10 +// CHECK-NEXT: line7 // CHECK-NEXT: col12 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line10 -// CHECK-NEXT: col24 +// CHECK-NEXT: line7 +// CHECK-NEXT: col14 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: end // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line13 +// CHECK-NEXT: line10 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line13 +// CHECK-NEXT: line10 // CHECK-NEXT: col8 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -260,7 +117,7 @@ void test() { // CHECK-NEXT: kindevent // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line13 +// CHECK-NEXT: line10 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -268,12 +125,12 @@ void test() { // CHECK-NEXT: // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line13 +// CHECK-NEXT: line10 // CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: // CHECK-NEXT: -// CHECK-NEXT: line13 +// CHECK-NEXT: line10 // CHECK-NEXT: col10 // CHECK-NEXT: file0 // CHECK-NEXT: @@ -295,7 +152,7 @@ void test() { // CHECK-NEXT: issue_hash4 // CHECK-NEXT: location // CHECK-NEXT: -// CHECK-NEXT: line13 +// CHECK-NEXT: line10 // CHECK-NEXT: col3 // CHECK-NEXT: file0 // CHECK-NEXT: diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp index c8e0acba7b..59b899f262 100644 --- a/test/CodeGenCXX/new.cpp +++ b/test/CodeGenCXX/new.cpp @@ -321,14 +321,14 @@ namespace N3664 { // CHECK-LABEL: define void @_ZN5N36641fEv void f() { // CHECK: call noalias i8* @_Znwm(i64 4) [[ATTR_BUILTIN_NEW:#[^ ]*]] - int *p = new int; // expected-note {{allocated with 'new' here}} + int *p = new int; // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE:#[^ ]*]] delete p; // CHECK: call noalias i8* @_Znam(i64 12) [[ATTR_BUILTIN_NEW]] int *q = new int[3]; // CHECK: call void @_ZdaPv({{.*}}) [[ATTR_BUILTIN_DELETE]] - delete[] p; // expected-warning {{'delete[]' applied to a pointer that was allocated with 'new'; did you mean 'delete'?}} + delete [] p; // CHECK: call i8* @_ZnamRKSt9nothrow_t(i64 3, {{.*}}) [[ATTR_BUILTIN_NOTHROW_NEW:#[^ ]*]] (void) new (nothrow) S[3]; diff --git a/test/SemaCXX/delete-mismatch.h b/test/SemaCXX/delete-mismatch.h deleted file mode 100644 index 84fcd611b6..0000000000 --- a/test/SemaCXX/delete-mismatch.h +++ /dev/null @@ -1,15 +0,0 @@ -// Header for PCH test delete.cpp -namespace pch_test { -struct X { - int *a; - X(); - X(int); - X(bool) - : a(new int[1]) { } // expected-note{{allocated with 'new[]' here}} - ~X() - { - delete a; // expected-warning{{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:9}:"[]" - } -}; -} diff --git a/test/SemaCXX/delete.cpp b/test/SemaCXX/delete.cpp index f808100a55..5824facc50 100644 --- a/test/SemaCXX/delete.cpp +++ b/test/SemaCXX/delete.cpp @@ -1,129 +1,9 @@ -// Test without PCH -// RUN: %clang_cc1 -fsyntax-only -include %S/delete-mismatch.h -fdiagnostics-parseable-fixits -std=c++11 %s 2>&1 | FileCheck %s - -// Test with PCH -// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t %S/delete-mismatch.h -// RUN: %clang_cc1 -std=c++11 -include-pch %t -DWITH_PCH -fsyntax-only -verify %s -ast-dump +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: cp %s %t +// RUN: %clang_cc1 -fixit -x c++ %t +// RUN: %clang_cc1 -E -o - %t | FileCheck %s void f(int a[10][20]) { + // CHECK: delete[] a; delete a; // expected-warning {{'delete' applied to a pointer-to-array type}} - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:9}:"[]" -} -namespace MemberCheck { -struct S { - int *a = new int[5]; // expected-note4 {{allocated with 'new[]' here}} - int *b; - int *c; - static int *d; - S(); - S(int); - ~S() { - delete a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - delete b; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - delete[] c; // expected-warning {{'delete[]' applied to a pointer that was allocated with 'new'; did you mean 'delete'?}} - } - void f(); -}; - -void S::f() -{ - delete a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - delete b; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} -} - -S::S() -: b(new int[1]), c(new int) {} // expected-note3 {{allocated with 'new[]' here}} -// expected-note@-1 {{allocated with 'new' here}} - -S::S(int i) -: b(new int[i]), c(new int) {} // expected-note3 {{allocated with 'new[]' here}} -// expected-note@-1 {{allocated with 'new' here}} - -struct S2 : S { - ~S2() { - delete a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - } -}; -int *S::d = new int[42]; // expected-note {{allocated with 'new[]' here}} -void f(S *s) { - int *a = new int[1]; // expected-note {{allocated with 'new[]' here}} - delete a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - delete s->a; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - delete s->b; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - delete s->c; - delete s->d; - delete S::d; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} -} - -// At least one constructor initializes field with matching form of 'new'. -struct MatchingNewIsOK { - int *p; - bool is_array_; - MatchingNewIsOK() : p{new int}, is_array_(false) {} - explicit MatchingNewIsOK(unsigned c) : p{new int[c]}, is_array_(true) {} - ~MatchingNewIsOK() { - if (is_array_) - delete[] p; - else - delete p; - } -}; - -// At least one constructor's body is missing; no proof of mismatch. -struct CantProve_MissingCtorDefinition { - int *p; - CantProve_MissingCtorDefinition(); - CantProve_MissingCtorDefinition(int); - ~CantProve_MissingCtorDefinition(); -}; - -CantProve_MissingCtorDefinition::CantProve_MissingCtorDefinition() - : p(new int) -{ } - -CantProve_MissingCtorDefinition::~CantProve_MissingCtorDefinition() -{ - delete[] p; -} - -struct base {}; -struct derived : base {}; -struct InitList { - base *p; - InitList() : p{new derived[1]} {} // expected-note {{allocated with 'new[]' here}} - explicit InitList(unsigned c) : p(new derived[c]) {} // expected-note {{allocated with 'new[]' here}} - InitList(unsigned c, unsigned) : p{new derived[c]} {} // expected-note {{allocated with 'new[]' here}} - InitList(const char *) : p{new derived[1]} {} // expected-note {{allocated with 'new[]' here}} - ~InitList() { - delete p; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - delete [] p; - } -}; -} - -namespace NonMemberCheck { -#define DELETE_ARRAY(x) delete[] (x) -#define DELETE(x) delete (x) -void f() { - int *a = new int(5); // expected-note2 {{allocated with 'new' here}} - delete[] a; // expected-warning {{'delete[]' applied to a pointer that was allocated with 'new'; did you mean 'delete'?}} - int *b = new int; - delete b; - int *c{new int}; // expected-note {{allocated with 'new' here}} - int *d{new int[1]}; // expected-note2 {{allocated with 'new[]' here}} - delete [ ] c; // expected-warning {{'delete[]' applied to a pointer that was allocated with 'new'; did you mean 'delete'?}} - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:17}:"" - delete d; // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} - // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:9}:"[]" - DELETE_ARRAY(a); // expected-warning {{'delete[]' applied to a pointer that was allocated with 'new'; did you mean 'delete'?}} - DELETE(d); // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}} -} } -#ifndef WITH_PCH -pch_test::X::X() - : a(new int[1]) // expected-note{{allocated with 'new[]' here}} -{ } -pch_test::X::X(int i) - : a(new int[i]) // expected-note{{allocated with 'new[]' here}} -{ } -#endif