<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, May 18, 2015 at 2:24 PM, Ismail Pazarbasi <span dir="ltr"><<a href="mailto:ismail.pazarbasi@gmail.com" target="_blank">ismail.pazarbasi@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Mon, May 18, 2015 at 11:12 PM, Ismail Pazarbasi<br>
<<a href="mailto:ismail.pazarbasi@gmail.com">ismail.pazarbasi@gmail.com</a>> wrote:<br>
> On Mon, May 18, 2015 at 10:57 PM, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br>
>> This has introduced a new warning:<br>
>><br>
>> include/clang/Serialization/ASTReader.h:1746:8: warning:<br>
>> 'ReadMismatchingDeleteExpressions' overrides a member function but is not<br>
>> marked 'override' [-Winconsistent-missing-override]<br>
>>   void ReadMismatchingDeleteExpressions(llvm::MapVector<<br>
>>        ^<br>
>> include/clang/Sema/ExternalSemaSource.h:83:16: note: overridden virtual<br>
>> function is here<br>
>>   virtual void ReadMismatchingDeleteExpressions(llvm::MapVector<<br>
>>                ^<br>
>><br>
>> Please can you fix this?<br>
> Yes, already landed in r237613.<br>
</span>I have added LLVM_ENABLE_WERROR to my build config, and currently rebuilding.<br>
<br>
Perhaps a cfe-dev discussion, but let me try here first; would it make<br>
sense to set LLVM_ENABLE_WERROR on by default?<br></blockquote><div><br></div><div>I think we had a thread on this some time last year. If I remember correctly, the reasoning for not doing this was that we don't know what compilers people will use to build clang and so we can't guarantee that it'll work. (Maybe someone suggested doing this for a whitelist of compilers – say in a bootstrap build – and then nobody did anything? But just blindly turning on -Werror won't work.)</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="HOEnZb"><div class="h5"><br>
><br>
>><br>
>> On Mon, May 18, 2015 at 12:59 PM, Ismail Pazarbasi<br>
>> <<a href="mailto:ismail.pazarbasi@gmail.com">ismail.pazarbasi@gmail.com</a>> wrote:<br>
>>><br>
>>> Author: ismailp<br>
>>> Date: Mon May 18 14:59:11 2015<br>
>>> New Revision: 237608<br>
>>><br>
>>> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=237608&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=237608&view=rev</a><br>
>>> Log:<br>
>>> Detect uses of mismatching forms of 'new' and 'delete'<br>
>>><br>
>>> Emit warning when operand to `delete` is allocated with `new[]` or<br>
>>> operand to `delete[]` is allocated with `new`.<br>
>>><br>
>>> rev 2 update:<br>
>>> `getNewExprFromInitListOrExpr` should return `dyn_cast_or_null`<br>
>>> instead of `dyn_cast`, since `E` might be null.<br>
>>><br>
>>> Reviewers: rtrieu, jordan_rose, rsmith<br>
>>><br>
>>> Subscribers: majnemer, cfe-commits<br>
>>><br>
>>> Differential Revision: <a href="http://reviews.llvm.org/D4661" target="_blank">http://reviews.llvm.org/D4661</a><br>
>>><br>
>>> Added:<br>
>>>     cfe/trunk/test/SemaCXX/delete-mismatch.h<br>
>>> Modified:<br>
>>>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
>>>     cfe/trunk/include/clang/Sema/ExternalSemaSource.h<br>
>>>     cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h<br>
>>>     cfe/trunk/include/clang/Sema/Sema.h<br>
>>>     cfe/trunk/include/clang/Serialization/ASTBitCodes.h<br>
>>>     cfe/trunk/include/clang/Serialization/ASTReader.h<br>
>>>     cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp<br>
>>>     cfe/trunk/lib/Sema/Sema.cpp<br>
>>>     cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>
>>>     cfe/trunk/lib/Serialization/ASTReader.cpp<br>
>>>     cfe/trunk/lib/Serialization/ASTWriter.cpp<br>
>>>     cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp<br>
>>>     cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm<br>
>>>     cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp<br>
>>>     cfe/trunk/test/CodeGenCXX/new.cpp<br>
>>>     cfe/trunk/test/SemaCXX/delete.cpp<br>
>>><br>
>>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
>>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon May 18<br>
>>> 14:59:11 2015<br>
>>> @@ -5516,7 +5516,12 @@ def err_delete_explicit_conversion : Err<br>
>>>    "conversion function">;<br>
>>>  def note_delete_conversion : Note<"conversion to pointer type %0">;<br>
>>>  def warn_delete_array_type : Warning<<br>
>>> -  "'delete' applied to a pointer-to-array type %0 treated as delete[]">;<br>
>>> +  "'delete' applied to a pointer-to-array type %0 treated as<br>
>>> 'delete[]'">;<br>
>>> +def warn_mismatched_delete_new : Warning<<br>
>>> +  "'delete%select{|[]}0' applied to a pointer that was allocated with "<br>
>>> +  "'new%select{[]|}0'; did you mean 'delete%select{[]|}0'?">,<br>
>>> +  InGroup<DiagGroup<"mismatched-new-delete">>;<br>
>>> +def note_allocated_here : Note<"allocated with 'new%select{[]|}0' here">;<br>
>>>  def err_no_suitable_delete_member_function_found : Error<<br>
>>>    "no suitable member %0 in %1">;<br>
>>>  def err_ambiguous_suitable_delete_member_function_found : Error<<br>
>>><br>
>>> Modified: cfe/trunk/include/clang/Sema/ExternalSemaSource.h<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ExternalSemaSource.h?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ExternalSemaSource.h?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/include/clang/Sema/ExternalSemaSource.h (original)<br>
>>> +++ cfe/trunk/include/clang/Sema/ExternalSemaSource.h Mon May 18 14:59:11<br>
>>> 2015<br>
>>> @@ -27,6 +27,7 @@ template <class T, unsigned n> class Sma<br>
>>>  namespace clang {<br>
>>><br>
>>>  class CXXConstructorDecl;<br>
>>> +class CXXDeleteExpr;<br>
>>>  class CXXRecordDecl;<br>
>>>  class DeclaratorDecl;<br>
>>>  class LookupResult;<br>
>>> @@ -79,6 +80,9 @@ public:<br>
>>>    virtual void ReadUndefinedButUsed(<br>
>>>                           llvm::DenseMap<NamedDecl*, SourceLocation><br>
>>> &Undefined);<br>
>>><br>
>>> +  virtual void ReadMismatchingDeleteExpressions(llvm::MapVector<<br>
>>> +      FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>><br>
>>> &);<br>
>>> +<br>
>>>    /// \brief Do last resort, unqualified lookup on a LookupResult that<br>
>>>    /// Sema cannot find.<br>
>>>    ///<br>
>>><br>
>>> Modified: cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h (original)<br>
>>> +++ cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h Mon May 18<br>
>>> 14:59:11 2015<br>
>>> @@ -230,6 +230,10 @@ public:<br>
>>>    void ReadUndefinedButUsed(<br>
>>>                  llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined)<br>
>>> override;<br>
>>><br>
>>> +  void ReadMismatchingDeleteExpressions(llvm::MapVector<<br>
>>> +      FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>><br>
>>> &<br>
>>> +                                            Exprs) override;<br>
>>> +<br>
>>>    /// \brief Do last resort, unqualified lookup on a LookupResult that<br>
>>>    /// Sema cannot find.<br>
>>>    ///<br>
>>><br>
>>> Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
>>> +++ cfe/trunk/include/clang/Sema/Sema.h Mon May 18 14:59:11 2015<br>
>>> @@ -78,6 +78,7 @@ namespace clang {<br>
>>>    typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;<br>
>>>    class CXXConstructorDecl;<br>
>>>    class CXXConversionDecl;<br>
>>> +  class CXXDeleteExpr;<br>
>>>    class CXXDestructorDecl;<br>
>>>    class CXXFieldCollector;<br>
>>>    class CXXMemberCallExpr;<br>
>>> @@ -404,6 +405,15 @@ public:<br>
>>>    llvm::SmallSetVector<const TypedefNameDecl *, 4><br>
>>>        UnusedLocalTypedefNameCandidates;<br>
>>><br>
>>> +  /// \brief Delete-expressions to be analyzed at the end of translation<br>
>>> unit<br>
>>> +  ///<br>
>>> +  /// This list contains class members, and locations of<br>
>>> delete-expressions<br>
>>> +  /// that could not be proven as to whether they mismatch with<br>
>>> new-expression<br>
>>> +  /// used in initializer of the field.<br>
>>> +  typedef std::pair<SourceLocation, bool> DeleteExprLoc;<br>
>>> +  typedef llvm::SmallVector<DeleteExprLoc, 4> DeleteLocs;<br>
>>> +  llvm::MapVector<FieldDecl *, DeleteLocs> DeleteExprs;<br>
>>> +<br>
>>>    typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy;<br>
>>><br>
>>>    /// PureVirtualClassDiagSet - a set of class declarations which we have<br>
>>> @@ -888,6 +898,11 @@ public:<br>
>>>    void getUndefinedButUsed(<br>
>>>        SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> ><br>
>>> &Undefined);<br>
>>><br>
>>> +  /// Retrieves list of suspicious delete-expressions that will be<br>
>>> checked at<br>
>>> +  /// the end of translation unit.<br>
>>> +  const llvm::MapVector<FieldDecl *, DeleteLocs> &<br>
>>> +  getMismatchingDeleteExpressions() const;<br>
>>> +<br>
>>>    typedef std::pair<ObjCMethodList, ObjCMethodList> GlobalMethods;<br>
>>>    typedef llvm::DenseMap<Selector, GlobalMethods> GlobalMethodPool;<br>
>>><br>
>>> @@ -8663,6 +8678,9 @@ private:<br>
>>>    /// attempts to add itself into the container<br>
>>>    void CheckObjCCircularContainer(ObjCMessageExpr *Message);<br>
>>><br>
>>> +  void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE);<br>
>>> +  void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation<br>
>>> DeleteLoc,<br>
>>> +                                 bool DeleteWasArrayForm);<br>
>>>  public:<br>
>>>    /// \brief Register a magic integral constant to be used as a type tag.<br>
>>>    void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,<br>
>>><br>
>>> Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)<br>
>>> +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Mon May 18<br>
>>> 14:59:11 2015<br>
>>> @@ -561,6 +561,9 @@ namespace clang {<br>
>>>        /// \brief Record code for the table of offsets to<br>
>>> CXXCtorInitializers<br>
>>>        /// lists.<br>
>>>        CXX_CTOR_INITIALIZERS_OFFSETS = 53,<br>
>>> +<br>
>>> +      /// \brief Delete expressions that will be analyzed later.<br>
>>> +      DELETE_EXPRS_TO_ANALYZE = 54<br>
>>>      };<br>
>>><br>
>>>      /// \brief Record types used within a source manager block.<br>
>>><br>
>>> Modified: cfe/trunk/include/clang/Serialization/ASTReader.h<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/include/clang/Serialization/ASTReader.h (original)<br>
>>> +++ cfe/trunk/include/clang/Serialization/ASTReader.h Mon May 18 14:59:11<br>
>>> 2015<br>
>>> @@ -760,6 +760,9 @@ private:<br>
>>>    /// SourceLocation of a matching ODR-use.<br>
>>>    SmallVector<uint64_t, 8> UndefinedButUsed;<br>
>>><br>
>>> +  /// \brief Delete expressions to analyze at the end of translation<br>
>>> unit.<br>
>>> +  SmallVector<uint64_t, 8> DelayedDeleteExprs;<br>
>>> +<br>
>>>    // \brief A list of late parsed template function data.<br>
>>>    SmallVector<uint64_t, 1> LateParsedTemplates;<br>
>>><br>
>>> @@ -1740,6 +1743,10 @@ public:<br>
>>>    void ReadUndefinedButUsed(<br>
>>>                 llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined)<br>
>>> override;<br>
>>><br>
>>> +  void ReadMismatchingDeleteExpressions(llvm::MapVector<<br>
>>> +      FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>><br>
>>> &<br>
>>> +                                            Exprs);<br>
>>> +<br>
>>>    void ReadTentativeDefinitions(<br>
>>>                              SmallVectorImpl<VarDecl *> &TentativeDefs)<br>
>>> override;<br>
>>><br>
>>><br>
>>> Modified: cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp (original)<br>
>>> +++ cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp Mon May 18 14:59:11<br>
>>> 2015<br>
>>> @@ -212,7 +212,15 @@ void MultiplexExternalSemaSource::ReadUn<br>
>>>    for(size_t i = 0; i < Sources.size(); ++i)<br>
>>>      Sources[i]->ReadUndefinedButUsed(Undefined);<br>
>>>  }<br>
>>> -<br>
>>> +<br>
>>> +void MultiplexExternalSemaSource::ReadMismatchingDeleteExpressions(<br>
>>> +    llvm::MapVector<FieldDecl *,<br>
>>> +                    llvm::SmallVector<std::pair<SourceLocation, bool>,<br>
>>> 4>> &<br>
>>> +        Exprs) {<br>
>>> +  for (auto &Source : Sources)<br>
>>> +    Source->ReadMismatchingDeleteExpressions(Exprs);<br>
>>> +}<br>
>>> +<br>
>>>  bool MultiplexExternalSemaSource::LookupUnqualified(LookupResult &R,<br>
>>> Scope *S){<br>
>>>    for(size_t i = 0; i < Sources.size(); ++i)<br>
>>>      Sources[i]->LookupUnqualified(R, S);<br>
>>><br>
>>> Modified: cfe/trunk/lib/Sema/Sema.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/Sema/Sema.cpp (original)<br>
>>> +++ cfe/trunk/lib/Sema/Sema.cpp Mon May 18 14:59:11 2015<br>
>>> @@ -861,6 +861,17 @@ void Sema::ActOnEndOfTranslationUnit() {<br>
>>>      }<br>
>>>    }<br>
>>><br>
>>> +  if (!Diags.isIgnored(diag::warn_mismatched_delete_new,<br>
>>> SourceLocation())) {<br>
>>> +    if (ExternalSource)<br>
>>> +      ExternalSource->ReadMismatchingDeleteExpressions(DeleteExprs);<br>
>>> +    for (const auto &DeletedFieldInfo : DeleteExprs) {<br>
>>> +      for (const auto &DeleteExprLoc : DeletedFieldInfo.second) {<br>
>>> +        AnalyzeDeleteExprMismatch(DeletedFieldInfo.first,<br>
>>> DeleteExprLoc.first,<br>
>>> +                                  DeleteExprLoc.second);<br>
>>> +      }<br>
>>> +    }<br>
>>> +  }<br>
>>> +<br>
>>>    // Check we've noticed that we're no longer parsing the initializer for<br>
>>> every<br>
>>>    // variable. If we miss cases, then at best we have a performance issue<br>
>>> and<br>
>>>    // at worst a rejects-valid bug.<br>
>>> @@ -1220,6 +1231,9 @@ void ExternalSemaSource::ReadUndefinedBu<br>
>>>                         llvm::DenseMap<NamedDecl *, SourceLocation><br>
>>> &Undefined) {<br>
>>>  }<br>
>>><br>
>>> +void<br>
>>> ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector<<br>
>>> +    FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>><br>
>>> &) {}<br>
>>> +<br>
>>>  void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const {<br>
>>>    SourceLocation Loc = this->Loc;<br>
>>>    if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation();<br>
>>> @@ -1468,3 +1482,8 @@ CapturedRegionScopeInfo *Sema::getCurCap<br>
>>><br>
>>>    return dyn_cast<CapturedRegionScopeInfo>(FunctionScopes.back());<br>
>>>  }<br>
>>> +<br>
>>> +const llvm::MapVector<FieldDecl *, Sema::DeleteLocs> &<br>
>>> +Sema::getMismatchingDeleteExpressions() const {<br>
>>> +  return DeleteExprs;<br>
>>> +}<br>
>>><br>
>>> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)<br>
>>> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon May 18 14:59:11 2015<br>
>>> @@ -2339,6 +2339,261 @@ bool Sema::FindDeallocationFunction(Sour<br>
>>>    return false;<br>
>>>  }<br>
>>><br>
>>> +namespace {<br>
>>> +/// \brief Checks whether delete-expression, and new-expression used for<br>
>>> +///  initializing deletee have the same array form.<br>
>>> +class MismatchingNewDeleteDetector {<br>
>>> +public:<br>
>>> +  enum MismatchResult {<br>
>>> +    /// Indicates that there is no mismatch or a mismatch cannot be<br>
>>> proven.<br>
>>> +    NoMismatch,<br>
>>> +    /// Indicates that variable is initialized with mismatching form of<br>
>>> \a new.<br>
>>> +    VarInitMismatches,<br>
>>> +    /// Indicates that member is initialized with mismatching form of \a<br>
>>> new.<br>
>>> +    MemberInitMismatches,<br>
>>> +    /// Indicates that 1 or more constructors' definitions could not been<br>
>>> +    /// analyzed, and they will be checked again at the end of<br>
>>> translation unit.<br>
>>> +    AnalyzeLater<br>
>>> +  };<br>
>>> +<br>
>>> +  /// \param EndOfTU True, if this is the final analysis at the end of<br>
>>> +  /// translation unit. False, if this is the initial analysis at the<br>
>>> point<br>
>>> +  /// delete-expression was encountered.<br>
>>> +  explicit MismatchingNewDeleteDetector(bool EndOfTU)<br>
>>> +      : IsArrayForm(false), Field(nullptr), EndOfTU(EndOfTU),<br>
>>> +        HasUndefinedConstructors(false) {}<br>
>>> +<br>
>>> +  /// \brief Checks whether pointee of a delete-expression is initialized<br>
>>> with<br>
>>> +  /// matching form of new-expression.<br>
>>> +  ///<br>
>>> +  /// If return value is \c VarInitMismatches or \c MemberInitMismatches<br>
>>> at the<br>
>>> +  /// point where delete-expression is encountered, then a warning will<br>
>>> be<br>
>>> +  /// issued immediately. If return value is \c AnalyzeLater at the point<br>
>>> where<br>
>>> +  /// delete-expression is seen, then member will be analyzed at the end<br>
>>> of<br>
>>> +  /// translation unit. \c AnalyzeLater is returned iff at least one<br>
>>> constructor<br>
>>> +  /// couldn't be analyzed. If at least one constructor initializes the<br>
>>> member<br>
>>> +  /// with matching type of new, the return value is \c NoMismatch.<br>
>>> +  MismatchResult analyzeDeleteExpr(const CXXDeleteExpr *DE);<br>
>>> +  /// \brief Analyzes a class member.<br>
>>> +  /// \param Field Class member to analyze.<br>
>>> +  /// \param DeleteWasArrayForm Array form-ness of the delete-expression<br>
>>> used<br>
>>> +  /// for deleting the \p Field.<br>
>>> +  MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm);<br>
>>> +  /// List of mismatching new-expressions used for initialization of the<br>
>>> pointee<br>
>>> +  llvm::SmallVector<const CXXNewExpr *, 4> NewExprs;<br>
>>> +  /// Indicates whether delete-expression was in array form.<br>
>>> +  bool IsArrayForm;<br>
>>> +  FieldDecl *Field;<br>
>>> +<br>
>>> +private:<br>
>>> +  const bool EndOfTU;<br>
>>> +  /// \brief Indicates that there is at least one constructor without<br>
>>> body.<br>
>>> +  bool HasUndefinedConstructors;<br>
>>> +  /// \brief Returns \c CXXNewExpr from given initialization expression.<br>
>>> +  /// \param E Expression used for initializing pointee in<br>
>>> delete-expression.<br>
>>> +  /// \param E can be a single-element \c InitListExpr consisting of<br>
>>> +  /// \param E new-expression.<br>
>>> +  const CXXNewExpr *getNewExprFromInitListOrExpr(const Expr *E);<br>
>>> +  /// \brief Returns whether member is initialized with mismatching form<br>
>>> of<br>
>>> +  /// \c new either by the member initializer or in-class initialization.<br>
>>> +  ///<br>
>>> +  /// If bodies of all constructors are not visible at the end of<br>
>>> translation<br>
>>> +  /// unit or at least one constructor initializes member with the<br>
>>> matching<br>
>>> +  /// form of \c new, mismatch cannot be proven, and this function will<br>
>>> return<br>
>>> +  /// \c NoMismatch.<br>
>>> +  MismatchResult analyzeMemberExpr(const MemberExpr *ME);<br>
>>> +  /// \brief Returns whether variable is initialized with mismatching<br>
>>> form of<br>
>>> +  /// \c new.<br>
>>> +  ///<br>
>>> +  /// If variable is initialized with matching form of \c new or variable<br>
>>> is not<br>
>>> +  /// initialized with a \c new expression, this function will return<br>
>>> true.<br>
>>> +  /// If variable is initialized with mismatching form of \c new, returns<br>
>>> false.<br>
>>> +  /// \param D Variable to analyze.<br>
>>> +  bool hasMatchingVarInit(const DeclRefExpr *D);<br>
>>> +  /// \brief Checks whether the constructor initializes pointee with<br>
>>> mismatching<br>
>>> +  /// form of \c new.<br>
>>> +  ///<br>
>>> +  /// Returns true, if member is initialized with matching form of \c new<br>
>>> in<br>
>>> +  /// member initializer list. Returns false, if member is initialized<br>
>>> with the<br>
>>> +  /// matching form of \c new in this constructor's initializer or given<br>
>>> +  /// constructor isn't defined at the point where delete-expression is<br>
>>> seen, or<br>
>>> +  /// member isn't initialized by the constructor.<br>
>>> +  bool hasMatchingNewInCtor(const CXXConstructorDecl *CD);<br>
>>> +  /// \brief Checks whether member is initialized with matching form of<br>
>>> +  /// \c new in member initializer list.<br>
>>> +  bool hasMatchingNewInCtorInit(const CXXCtorInitializer *CI);<br>
>>> +  /// Checks whether member is initialized with mismatching form of \c<br>
>>> new by<br>
>>> +  /// in-class initializer.<br>
>>> +  MismatchResult analyzeInClassInitializer();<br>
>>> +};<br>
>>> +}<br>
>>> +<br>
>>> +MismatchingNewDeleteDetector::MismatchResult<br>
>>> +MismatchingNewDeleteDetector::analyzeDeleteExpr(const CXXDeleteExpr *DE)<br>
>>> {<br>
>>> +  NewExprs.clear();<br>
>>> +  assert(DE && "Expected delete-expression");<br>
>>> +  IsArrayForm = DE->isArrayForm();<br>
>>> +  const Expr *E = DE->getArgument()->IgnoreParenImpCasts();<br>
>>> +  if (const MemberExpr *ME = dyn_cast<const MemberExpr>(E)) {<br>
>>> +    return analyzeMemberExpr(ME);<br>
>>> +  } else if (const DeclRefExpr *D = dyn_cast<const DeclRefExpr>(E)) {<br>
>>> +    if (!hasMatchingVarInit(D))<br>
>>> +      return VarInitMismatches;<br>
>>> +  }<br>
>>> +  return NoMismatch;<br>
>>> +}<br>
>>> +<br>
>>> +const CXXNewExpr *<br>
>>> +MismatchingNewDeleteDetector::getNewExprFromInitListOrExpr(const Expr *E)<br>
>>> {<br>
>>> +  assert(E != nullptr && "Expected a valid initializer expression");<br>
>>> +  E = E->IgnoreParenImpCasts();<br>
>>> +  if (const InitListExpr *ILE = dyn_cast<const InitListExpr>(E)) {<br>
>>> +    if (ILE->getNumInits() == 1)<br>
>>> +      E = dyn_cast<const<br>
>>> CXXNewExpr>(ILE->getInit(0)->IgnoreParenImpCasts());<br>
>>> +  }<br>
>>> +<br>
>>> +  return dyn_cast_or_null<const CXXNewExpr>(E);<br>
>>> +}<br>
>>> +<br>
>>> +bool MismatchingNewDeleteDetector::hasMatchingNewInCtorInit(<br>
>>> +    const CXXCtorInitializer *CI) {<br>
>>> +  const CXXNewExpr *NE = nullptr;<br>
>>> +  if (Field == CI->getMember() &&<br>
>>> +      (NE = getNewExprFromInitListOrExpr(CI->getInit()))) {<br>
>>> +    if (NE->isArray() == IsArrayForm)<br>
>>> +      return true;<br>
>>> +    else<br>
>>> +      NewExprs.push_back(NE);<br>
>>> +  }<br>
>>> +  return false;<br>
>>> +}<br>
>>> +<br>
>>> +bool MismatchingNewDeleteDetector::hasMatchingNewInCtor(<br>
>>> +    const CXXConstructorDecl *CD) {<br>
>>> +  if (CD->isImplicit())<br>
>>> +    return false;<br>
>>> +  const FunctionDecl *Definition = CD;<br>
>>> +  if (!CD->isThisDeclarationADefinition() && !CD->isDefined(Definition))<br>
>>> {<br>
>>> +    HasUndefinedConstructors = true;<br>
>>> +    return EndOfTU;<br>
>>> +  }<br>
>>> +  for (const auto *CI : cast<const<br>
>>> CXXConstructorDecl>(Definition)->inits()) {<br>
>>> +    if (hasMatchingNewInCtorInit(CI))<br>
>>> +      return true;<br>
>>> +  }<br>
>>> +  return false;<br>
>>> +}<br>
>>> +<br>
>>> +MismatchingNewDeleteDetector::MismatchResult<br>
>>> +MismatchingNewDeleteDetector::analyzeInClassInitializer() {<br>
>>> +  assert(Field != nullptr && "This should be called only for members");<br>
>>> +  if (const CXXNewExpr *NE =<br>
>>> +          getNewExprFromInitListOrExpr(Field->getInClassInitializer())) {<br>
>>> +    if (NE->isArray() != IsArrayForm) {<br>
>>> +      NewExprs.push_back(NE);<br>
>>> +      return MemberInitMismatches;<br>
>>> +    }<br>
>>> +  }<br>
>>> +  return NoMismatch;<br>
>>> +}<br>
>>> +<br>
>>> +MismatchingNewDeleteDetector::MismatchResult<br>
>>> +MismatchingNewDeleteDetector::analyzeField(FieldDecl *Field,<br>
>>> +                                           bool DeleteWasArrayForm) {<br>
>>> +  assert(Field != nullptr && "Analysis requires a valid class member.");<br>
>>> +  this->Field = Field;<br>
>>> +  IsArrayForm = DeleteWasArrayForm;<br>
>>> +  const CXXRecordDecl *RD = cast<const<br>
>>> CXXRecordDecl>(Field->getParent());<br>
>>> +  for (const auto *CD : RD->ctors()) {<br>
>>> +    if (hasMatchingNewInCtor(CD))<br>
>>> +      return NoMismatch;<br>
>>> +  }<br>
>>> +  if (HasUndefinedConstructors)<br>
>>> +    return EndOfTU ? NoMismatch : AnalyzeLater;<br>
>>> +  if (!NewExprs.empty())<br>
>>> +    return MemberInitMismatches;<br>
>>> +  return Field->hasInClassInitializer() ? analyzeInClassInitializer()<br>
>>> +                                        : NoMismatch;<br>
>>> +}<br>
>>> +<br>
>>> +MismatchingNewDeleteDetector::MismatchResult<br>
>>> +MismatchingNewDeleteDetector::analyzeMemberExpr(const MemberExpr *ME) {<br>
>>> +  assert(ME != nullptr && "Expected a member expression");<br>
>>> +  if (FieldDecl *F = dyn_cast<FieldDecl>(ME->getMemberDecl()))<br>
>>> +    return analyzeField(F, IsArrayForm);<br>
>>> +  return NoMismatch;<br>
>>> +}<br>
>>> +<br>
>>> +bool MismatchingNewDeleteDetector::hasMatchingVarInit(const DeclRefExpr<br>
>>> *D) {<br>
>>> +  const CXXNewExpr *NE = nullptr;<br>
>>> +  if (const VarDecl *VD = dyn_cast<const VarDecl>(D->getDecl())) {<br>
>>> +    if (VD->hasInit() && (NE =<br>
>>> getNewExprFromInitListOrExpr(VD->getInit())) &&<br>
>>> +        NE->isArray() != IsArrayForm) {<br>
>>> +      NewExprs.push_back(NE);<br>
>>> +    }<br>
>>> +  }<br>
>>> +  return NewExprs.empty();<br>
>>> +}<br>
>>> +<br>
>>> +static void<br>
>>> +DiagnoseMismatchedNewDelete(Sema &SemaRef, SourceLocation DeleteLoc,<br>
>>> +                            const MismatchingNewDeleteDetector &Detector)<br>
>>> {<br>
>>> +  SourceLocation EndOfDelete = SemaRef.getLocForEndOfToken(DeleteLoc);<br>
>>> +  FixItHint H;<br>
>>> +  if (!Detector.IsArrayForm)<br>
>>> +    H = FixItHint::CreateInsertion(EndOfDelete, "[]");<br>
>>> +  else {<br>
>>> +    SourceLocation RSquare = Lexer::findLocationAfterToken(<br>
>>> +        DeleteLoc, tok::l_square, SemaRef.getSourceManager(),<br>
>>> +        SemaRef.getLangOpts(), true);<br>
>>> +    if (RSquare.isValid())<br>
>>> +      H = FixItHint::CreateRemoval(SourceRange(EndOfDelete, RSquare));<br>
>>> +  }<br>
>>> +  SemaRef.Diag(DeleteLoc, diag::warn_mismatched_delete_new)<br>
>>> +      << Detector.IsArrayForm << H;<br>
>>> +<br>
>>> +  for (const auto *NE : Detector.NewExprs)<br>
>>> +    SemaRef.Diag(NE->getExprLoc(), diag::note_allocated_here)<br>
>>> +        << Detector.IsArrayForm;<br>
>>> +}<br>
>>> +<br>
>>> +void Sema::AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE) {<br>
>>> +  if (Diags.isIgnored(diag::warn_mismatched_delete_new,<br>
>>> SourceLocation()))<br>
>>> +    return;<br>
>>> +  MismatchingNewDeleteDetector Detector(/*EndOfTU=*/false);<br>
>>> +  switch (Detector.analyzeDeleteExpr(DE)) {<br>
>>> +  case MismatchingNewDeleteDetector::VarInitMismatches:<br>
>>> +  case MismatchingNewDeleteDetector::MemberInitMismatches: {<br>
>>> +    DiagnoseMismatchedNewDelete(*this, DE->getLocStart(), Detector);<br>
>>> +    break;<br>
>>> +  }<br>
>>> +  case MismatchingNewDeleteDetector::AnalyzeLater: {<br>
>>> +    DeleteExprs[Detector.Field].push_back(<br>
>>> +        std::make_pair(DE->getLocStart(), DE->isArrayForm()));<br>
>>> +    break;<br>
>>> +  }<br>
>>> +  case MismatchingNewDeleteDetector::NoMismatch:<br>
>>> +    break;<br>
>>> +  }<br>
>>> +}<br>
>>> +<br>
>>> +void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation<br>
>>> DeleteLoc,<br>
>>> +                                     bool DeleteWasArrayForm) {<br>
>>> +  MismatchingNewDeleteDetector Detector(/*EndOfTU=*/true);<br>
>>> +  switch (Detector.analyzeField(Field, DeleteWasArrayForm)) {<br>
>>> +  case MismatchingNewDeleteDetector::VarInitMismatches:<br>
>>> +    llvm_unreachable("This analysis should have been done for class<br>
>>> members.");<br>
>>> +  case MismatchingNewDeleteDetector::AnalyzeLater:<br>
>>> +    llvm_unreachable("Analysis cannot be postponed any point beyond end<br>
>>> of "<br>
>>> +                     "translation unit.");<br>
>>> +  case MismatchingNewDeleteDetector::MemberInitMismatches:<br>
>>> +    DiagnoseMismatchedNewDelete(*this, DeleteLoc, Detector);<br>
>>> +    break;<br>
>>> +  case MismatchingNewDeleteDetector::NoMismatch:<br>
>>> +    break;<br>
>>> +  }<br>
>>> +}<br>
>>> +<br>
>>>  /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in:<br>
>>>  /// @code ::delete ptr; @endcode<br>
>>>  /// or<br>
>>> @@ -2454,12 +2709,6 @@ Sema::ActOnCXXDelete(SourceLocation Star<br>
>>>        }<br>
>>>      }<br>
>>><br>
>>> -    // C++ [expr.delete]p2:<br>
>>> -    //   [Note: a pointer to a const type can be the operand of a<br>
>>> -    //   delete-expression; it is not necessary to cast away the<br>
>>> constness<br>
>>> -    //   (5.2.11) of the pointer expression before it is used as the<br>
>>> operand<br>
>>> -    //   of the delete-expression. ]<br>
>>> -<br>
>>>      if (Pointee->isArrayType() && !ArrayForm) {<br>
>>>        Diag(StartLoc, diag::warn_delete_array_type)<br>
>>>            << Type << Ex.get()->getSourceRange()<br>
>>> @@ -2534,7 +2783,7 @@ Sema::ActOnCXXDelete(SourceLocation Star<br>
>>>            DeleteName);<br>
>>><br>
>>>      MarkFunctionReferenced(StartLoc, OperatorDelete);<br>
>>> -<br>
>>> +<br>
>>>      // Check access and ambiguity of operator delete and destructor.<br>
>>>      if (PointeeRD) {<br>
>>>        if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {<br>
>>> @@ -2544,9 +2793,11 @@ Sema::ActOnCXXDelete(SourceLocation Star<br>
>>>      }<br>
>>>    }<br>
>>><br>
>>> -  return new (Context) CXXDeleteExpr(<br>
>>> +  CXXDeleteExpr *Result = new (Context) CXXDeleteExpr(<br>
>>>        Context.VoidTy, UseGlobal, ArrayForm, ArrayFormAsWritten,<br>
>>>        UsualArrayDeleteWantsSize, OperatorDelete, Ex.get(), StartLoc);<br>
>>> +  AnalyzeDeleteExprMismatch(Result);<br>
>>> +  return Result;<br>
>>>  }<br>
>>><br>
>>>  /// \brief Check the use of the given variable as a C++ condition in an<br>
>>> if,<br>
>>><br>
>>> Modified: cfe/trunk/lib/Serialization/ASTReader.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/Serialization/ASTReader.cpp (original)<br>
>>> +++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon May 18 14:59:11 2015<br>
>>> @@ -3021,6 +3021,18 @@ ASTReader::ReadASTBlock(ModuleFile &F, u<br>
>>>              ReadSourceLocation(F, Record, I).getRawEncoding());<br>
>>>        }<br>
>>>        break;<br>
>>> +    case DELETE_EXPRS_TO_ANALYZE:<br>
>>> +      for (unsigned I = 0, N = Record.size(); I != N;) {<br>
>>> +        DelayedDeleteExprs.push_back(getGlobalDeclID(F, Record[I++]));<br>
>>> +        const uint64_t Count = Record[I++];<br>
>>> +        DelayedDeleteExprs.push_back(Count);<br>
>>> +        for (uint64_t C = 0; C < Count; ++C) {<br>
>>> +          DelayedDeleteExprs.push_back(ReadSourceLocation(F, Record,<br>
>>> I).getRawEncoding());<br>
>>> +          bool IsArrayForm = Record[I++] == 1;<br>
>>> +          DelayedDeleteExprs.push_back(IsArrayForm);<br>
>>> +        }<br>
>>> +      }<br>
>>> +      break;<br>
>>><br>
>>>      case IMPORTED_MODULES: {<br>
>>>        if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) {<br>
>>> @@ -7016,6 +7028,21 @@ void ASTReader::ReadUndefinedButUsed(<br>
>>>    }<br>
>>>  }<br>
>>><br>
>>> +void ASTReader::ReadMismatchingDeleteExpressions(llvm::MapVector<<br>
>>> +    FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &<br>
>>> +                                                     Exprs) {<br>
>>> +  for (unsigned Idx = 0, N = DelayedDeleteExprs.size(); Idx != N;) {<br>
>>> +    FieldDecl *FD = cast<FieldDecl>(GetDecl(DelayedDeleteExprs[Idx++]));<br>
>>> +    uint64_t Count = DelayedDeleteExprs[Idx++];<br>
>>> +    for (uint64_t C = 0; C < Count; ++C) {<br>
>>> +      SourceLocation DeleteLoc =<br>
>>> +          SourceLocation::getFromRawEncoding(DelayedDeleteExprs[Idx++]);<br>
>>> +      const bool IsArrayForm = DelayedDeleteExprs[Idx++];<br>
>>> +      Exprs[FD].push_back(std::make_pair(DeleteLoc, IsArrayForm));<br>
>>> +    }<br>
>>> +  }<br>
>>> +}<br>
>>> +<br>
>>>  void ASTReader::ReadTentativeDefinitions(<br>
>>>                    SmallVectorImpl<VarDecl *> &TentativeDefs) {<br>
>>>    for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {<br>
>>><br>
>>> Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)<br>
>>> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon May 18 14:59:11 2015<br>
>>> @@ -4155,6 +4155,20 @@ void ASTWriter::WriteASTCore(Sema &SemaR<br>
>>>      AddSourceLocation(I->second, UndefinedButUsed);<br>
>>>    }<br>
>>><br>
>>> +  // Build a record containing all delete-expressions that we would like<br>
>>> to<br>
>>> +  // analyze later in AST.<br>
>>> +  RecordData DeleteExprsToAnalyze;<br>
>>> +<br>
>>> +  for (const auto &DeleteExprsInfo :<br>
>>> +       SemaRef.getMismatchingDeleteExpressions()) {<br>
>>> +    AddDeclRef(DeleteExprsInfo.first, DeleteExprsToAnalyze);<br>
>>> +    DeleteExprsToAnalyze.push_back(DeleteExprsInfo.second.size());<br>
>>> +    for (const auto &DeleteLoc : DeleteExprsInfo.second) {<br>
>>> +      AddSourceLocation(DeleteLoc.first, DeleteExprsToAnalyze);<br>
>>> +      DeleteExprsToAnalyze.push_back(DeleteLoc.second);<br>
>>> +    }<br>
>>> +  }<br>
>>> +<br>
>>>    // Write the control block<br>
>>>    WriteControlBlock(PP, Context, isysroot, OutputFile);<br>
>>><br>
>>> @@ -4424,7 +4438,10 @@ void ASTWriter::WriteASTCore(Sema &SemaR<br>
>>>    // Write the undefined internal functions and variables, and inline<br>
>>> functions.<br>
>>>    if (!UndefinedButUsed.empty())<br>
>>>      Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);<br>
>>> -<br>
>>> +<br>
>>> +  if (!DeleteExprsToAnalyze.empty())<br>
>>> +    Stream.EmitRecord(DELETE_EXPRS_TO_ANALYZE, DeleteExprsToAnalyze);<br>
>>> +<br>
>>>    // Write the visible updates to DeclContexts.<br>
>>>    for (auto *DC : UpdatedDeclContexts)<br>
>>>      WriteDeclContextVisibleUpdate(DC);<br>
>>><br>
>>> Modified:<br>
>>> cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Malloc%2BMismatchedDeallocator%2BNewDelete.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Malloc%2BMismatchedDeallocator%2BNewDelete.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp<br>
>>> (original)<br>
>>> +++ cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp Mon<br>
>>> May 18 14:59:11 2015<br>
>>> @@ -97,9 +97,11 @@ void testShouldReportDoubleFreeNotMismat<br>
>>>    free(p);<br>
>>>    delete globalPtr; // expected-warning {{Attempt to free released<br>
>>> memory}}<br>
>>>  }<br>
>>> -<br>
>>> +int *allocIntArray(unsigned c) {<br>
>>> +  return new int[c];<br>
>>> +}<br>
>>>  void testMismatchedChangePointeeThroughAssignment() {<br>
>>> -  int *arr = new int[4];<br>
>>> +  int *arr = allocIntArray(4);<br>
>>>    globalPtr = arr;<br>
>>>    delete arr; // expected-warning{{Memory allocated by 'new[]' should be<br>
>>> deallocated by 'delete[]', not 'delete'}}<br>
>>> -}<br>
>>> \ No newline at end of file<br>
>>> +}<br>
>>><br>
>>> Modified: cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm<br>
>>> (original)<br>
>>> +++ cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm Mon May<br>
>>> 18 14:59:11 2015<br>
>>> @@ -95,8 +95,11 @@ void testNew6() {<br>
>>>    realloc(p, sizeof(long)); // expected-warning{{Memory allocated by<br>
>>> 'new[]' should be deallocated by 'delete[]', not realloc()}}<br>
>>>  }<br>
>>><br>
>>> +int *allocInt() {<br>
>>> +  return new int;<br>
>>> +}<br>
>>>  void testNew7() {<br>
>>> -  int *p = new int;<br>
>>> +  int *p = allocInt();<br>
>>>    delete[] p; // expected-warning{{Memory allocated by 'new' should be<br>
>>> deallocated by 'delete', not 'delete[]'}}<br>
>>>  }<br>
>>><br>
>>> @@ -105,8 +108,12 @@ void testNew8() {<br>
>>>    delete[] p; // expected-warning{{Memory allocated by operator new<br>
>>> should be deallocated by 'delete', not 'delete[]'}}<br>
>>>  }<br>
>>><br>
>>> +int *allocIntArray(unsigned c) {<br>
>>> +  return new int[c];<br>
>>> +}<br>
>>> +<br>
>>>  void testNew9() {<br>
>>> -  int *p = new int[1];<br>
>>> +  int *p = allocIntArray(1);<br>
>>>    delete p; // expected-warning{{Memory allocated by 'new[]' should be<br>
>>> deallocated by 'delete[]', not 'delete'}}<br>
>>>  }<br>
>>><br>
>>><br>
>>> Modified: cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp<br>
>>> (original)<br>
>>> +++ cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp Mon May<br>
>>> 18 14:59:11 2015<br>
>>> @@ -3,9 +3,12 @@<br>
>>>  // RUN: FileCheck --input-file=%t.plist %s<br>
>>><br>
>>>  void changePointee(int *p);<br>
>>> +int *allocIntArray(unsigned c) {<br>
>>> +  return new int[c]; // expected-note {{Memory is allocated}}<br>
>>> +}<br>
>>>  void test() {<br>
>>> -  int *p = new int[1];<br>
>>> -  // expected-note@-1 {{Memory is allocated}}<br>
>>> +  int *p = allocIntArray(1); // expected-note {{Calling 'allocIntArray'}}<br>
>>> +  // expected-note@-1 {{Returned allocated memory}}<br>
>>>    changePointee(p);<br>
>>>    delete p; // expected-warning {{Memory allocated by 'new[]' should be<br>
>>> deallocated by 'delete[]', not 'delete'}}<br>
>>>    // expected-note@-1 {{Memory allocated by 'new[]' should be deallocated<br>
>>> by 'delete[]', not 'delete'}}<br>
>>> @@ -24,13 +27,124 @@ void test() {<br>
>>>  // CHECK-NEXT:        <key>start</key><br>
>>>  // CHECK-NEXT:         <array><br>
>>>  // CHECK-NEXT:          <dict><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>3</integer><br>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:          </dict><br>
>>> +// CHECK-NEXT:          <dict><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>5</integer><br>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:          </dict><br>
>>> +// CHECK-NEXT:         </array><br>
>>> +// CHECK-NEXT:        <key>end</key><br>
>>> +// CHECK-NEXT:         <array><br>
>>> +// CHECK-NEXT:          <dict><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>12</integer><br>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:          </dict><br>
>>> +// CHECK-NEXT:          <dict><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>24</integer><br>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:          </dict><br>
>>> +// CHECK-NEXT:         </array><br>
>>> +// CHECK-NEXT:       </dict><br>
>>> +// CHECK-NEXT:      </array><br>
>>> +// CHECK-NEXT:    </dict><br>
>>> +// CHECK-NEXT:    <dict><br>
>>> +// CHECK-NEXT:     <key>kind</key><string>event</string><br>
>>> +// CHECK-NEXT:     <key>location</key><br>
>>> +// CHECK-NEXT:     <dict><br>
>>> +// CHECK-NEXT:      <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:      <key>col</key><integer>12</integer><br>
>>> +// CHECK-NEXT:      <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:     </dict><br>
>>> +// CHECK-NEXT:     <key>ranges</key><br>
>>> +// CHECK-NEXT:     <array><br>
>>> +// CHECK-NEXT:       <array><br>
>>> +// CHECK-NEXT:        <dict><br>
>>> +// CHECK-NEXT:         <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:         <key>col</key><integer>12</integer><br>
>>> +// CHECK-NEXT:         <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:        </dict><br>
>>> +// CHECK-NEXT:        <dict><br>
>>> +// CHECK-NEXT:         <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:         <key>col</key><integer>27</integer><br>
>>> +// CHECK-NEXT:         <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:        </dict><br>
>>> +// CHECK-NEXT:       </array><br>
>>> +// CHECK-NEXT:     </array><br>
>>> +// CHECK-NEXT:     <key>depth</key><integer>0</integer><br>
>>> +// CHECK-NEXT:     <key>extended_message</key><br>
>>> +// CHECK-NEXT:     <string>Calling &apos;allocIntArray&apos;</string><br>
>>> +// CHECK-NEXT:     <key>message</key><br>
>>> +// CHECK-NEXT:     <string>Calling &apos;allocIntArray&apos;</string><br>
>>> +// CHECK-NEXT:    </dict><br>
>>> +// CHECK-NEXT:    <dict><br>
>>> +// CHECK-NEXT:     <key>kind</key><string>event</string><br>
>>> +// CHECK-NEXT:     <key>location</key><br>
>>> +// CHECK-NEXT:     <dict><br>
>>> +// CHECK-NEXT:      <key>line</key><integer>6</integer><br>
>>> +// CHECK-NEXT:      <key>col</key><integer>1</integer><br>
>>> +// CHECK-NEXT:      <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:     </dict><br>
>>> +// CHECK-NEXT:     <key>depth</key><integer>1</integer><br>
>>> +// CHECK-NEXT:     <key>extended_message</key><br>
>>> +// CHECK-NEXT:     <string>Entered call from &apos;test&apos;</string><br>
>>> +// CHECK-NEXT:     <key>message</key><br>
>>> +// CHECK-NEXT:     <string>Entered call from &apos;test&apos;</string><br>
>>> +// CHECK-NEXT:    </dict><br>
>>> +// CHECK-NEXT:    <dict><br>
>>> +// CHECK-NEXT:     <key>kind</key><string>control</string><br>
>>> +// CHECK-NEXT:     <key>edges</key><br>
>>> +// CHECK-NEXT:      <array><br>
>>> +// CHECK-NEXT:       <dict><br>
>>> +// CHECK-NEXT:        <key>start</key><br>
>>> +// CHECK-NEXT:         <array><br>
>>> +// CHECK-NEXT:          <dict><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>6</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>1</integer><br>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:          </dict><br>
>>> +// CHECK-NEXT:          <dict><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>6</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>3</integer><br>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:          </dict><br>
>>> +// CHECK-NEXT:         </array><br>
>>> +// CHECK-NEXT:        <key>end</key><br>
>>> +// CHECK-NEXT:         <array><br>
>>> +// CHECK-NEXT:          <dict><br>
>>>  // CHECK-NEXT:           <key>line</key><integer>7</integer><br>
>>>  // CHECK-NEXT:           <key>col</key><integer>3</integer><br>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:          </dict><br>
>>>  // CHECK-NEXT:          <dict><br>
>>>  // CHECK-NEXT:           <key>line</key><integer>7</integer><br>
>>> -// CHECK-NEXT:           <key>col</key><integer>5</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>8</integer><br>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:          </dict><br>
>>> +// CHECK-NEXT:         </array><br>
>>> +// CHECK-NEXT:       </dict><br>
>>> +// CHECK-NEXT:      </array><br>
>>> +// CHECK-NEXT:    </dict><br>
>>> +// CHECK-NEXT:    <dict><br>
>>> +// CHECK-NEXT:     <key>kind</key><string>control</string><br>
>>> +// CHECK-NEXT:     <key>edges</key><br>
>>> +// CHECK-NEXT:      <array><br>
>>> +// CHECK-NEXT:       <dict><br>
>>> +// CHECK-NEXT:        <key>start</key><br>
>>> +// CHECK-NEXT:         <array><br>
>>> +// CHECK-NEXT:          <dict><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>7</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>3</integer><br>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:          </dict><br>
>>> +// CHECK-NEXT:          <dict><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>7</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>8</integer><br>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:          </dict><br>
>>>  // CHECK-NEXT:         </array><br>
>>> @@ -38,12 +152,12 @@ void test() {<br>
>>>  // CHECK-NEXT:         <array><br>
>>>  // CHECK-NEXT:          <dict><br>
>>>  // CHECK-NEXT:           <key>line</key><integer>7</integer><br>
>>> -// CHECK-NEXT:           <key>col</key><integer>12</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>10</integer><br>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:          </dict><br>
>>>  // CHECK-NEXT:          <dict><br>
>>>  // CHECK-NEXT:           <key>line</key><integer>7</integer><br>
>>> -// CHECK-NEXT:           <key>col</key><integer>14</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>12</integer><br>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:          </dict><br>
>>>  // CHECK-NEXT:         </array><br>
>>> @@ -55,7 +169,7 @@ void test() {<br>
>>>  // CHECK-NEXT:     <key>location</key><br>
>>>  // CHECK-NEXT:     <dict><br>
>>>  // CHECK-NEXT:      <key>line</key><integer>7</integer><br>
>>> -// CHECK-NEXT:      <key>col</key><integer>12</integer><br>
>>> +// CHECK-NEXT:      <key>col</key><integer>10</integer><br>
>>>  // CHECK-NEXT:      <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:     </dict><br>
>>>  // CHECK-NEXT:     <key>ranges</key><br>
>>> @@ -63,23 +177,52 @@ void test() {<br>
>>>  // CHECK-NEXT:       <array><br>
>>>  // CHECK-NEXT:        <dict><br>
>>>  // CHECK-NEXT:         <key>line</key><integer>7</integer><br>
>>> -// CHECK-NEXT:         <key>col</key><integer>12</integer><br>
>>> +// CHECK-NEXT:         <key>col</key><integer>10</integer><br>
>>>  // CHECK-NEXT:         <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:        </dict><br>
>>>  // CHECK-NEXT:        <dict><br>
>>>  // CHECK-NEXT:         <key>line</key><integer>7</integer><br>
>>> -// CHECK-NEXT:         <key>col</key><integer>21</integer><br>
>>> +// CHECK-NEXT:         <key>col</key><integer>19</integer><br>
>>>  // CHECK-NEXT:         <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:        </dict><br>
>>>  // CHECK-NEXT:       </array><br>
>>>  // CHECK-NEXT:     </array><br>
>>> -// CHECK-NEXT:     <key>depth</key><integer>0</integer><br>
>>> +// CHECK-NEXT:     <key>depth</key><integer>1</integer><br>
>>>  // CHECK-NEXT:     <key>extended_message</key><br>
>>>  // CHECK-NEXT:     <string>Memory is allocated</string><br>
>>>  // CHECK-NEXT:     <key>message</key><br>
>>>  // CHECK-NEXT:     <string>Memory is allocated</string><br>
>>>  // CHECK-NEXT:    </dict><br>
>>>  // CHECK-NEXT:    <dict><br>
>>> +// CHECK-NEXT:     <key>kind</key><string>event</string><br>
>>> +// CHECK-NEXT:     <key>location</key><br>
>>> +// CHECK-NEXT:     <dict><br>
>>> +// CHECK-NEXT:      <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:      <key>col</key><integer>12</integer><br>
>>> +// CHECK-NEXT:      <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:     </dict><br>
>>> +// CHECK-NEXT:     <key>ranges</key><br>
>>> +// CHECK-NEXT:     <array><br>
>>> +// CHECK-NEXT:       <array><br>
>>> +// CHECK-NEXT:        <dict><br>
>>> +// CHECK-NEXT:         <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:         <key>col</key><integer>12</integer><br>
>>> +// CHECK-NEXT:         <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:        </dict><br>
>>> +// CHECK-NEXT:        <dict><br>
>>> +// CHECK-NEXT:         <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:         <key>col</key><integer>27</integer><br>
>>> +// CHECK-NEXT:         <key>file</key><integer>0</integer><br>
>>> +// CHECK-NEXT:        </dict><br>
>>> +// CHECK-NEXT:       </array><br>
>>> +// CHECK-NEXT:     </array><br>
>>> +// CHECK-NEXT:     <key>depth</key><integer>0</integer><br>
>>> +// CHECK-NEXT:     <key>extended_message</key><br>
>>> +// CHECK-NEXT:     <string>Returned allocated memory</string><br>
>>> +// CHECK-NEXT:     <key>message</key><br>
>>> +// CHECK-NEXT:     <string>Returned allocated memory</string><br>
>>> +// CHECK-NEXT:    </dict><br>
>>> +// CHECK-NEXT:    <dict><br>
>>>  // CHECK-NEXT:     <key>kind</key><string>control</string><br>
>>>  // CHECK-NEXT:     <key>edges</key><br>
>>>  // CHECK-NEXT:      <array><br>
>>> @@ -87,25 +230,25 @@ void test() {<br>
>>>  // CHECK-NEXT:        <key>start</key><br>
>>>  // CHECK-NEXT:         <array><br>
>>>  // CHECK-NEXT:          <dict><br>
>>> -// CHECK-NEXT:           <key>line</key><integer>7</integer><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer><br>
>>>  // CHECK-NEXT:           <key>col</key><integer>12</integer><br>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:          </dict><br>
>>>  // CHECK-NEXT:          <dict><br>
>>> -// CHECK-NEXT:           <key>line</key><integer>7</integer><br>
>>> -// CHECK-NEXT:           <key>col</key><integer>14</integer><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:           <key>col</key><integer>24</integer><br>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:          </dict><br>
>>>  // CHECK-NEXT:         </array><br>
>>>  // CHECK-NEXT:        <key>end</key><br>
>>>  // CHECK-NEXT:         <array><br>
>>>  // CHECK-NEXT:          <dict><br>
>>> -// CHECK-NEXT:           <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>13</integer><br>
>>>  // CHECK-NEXT:           <key>col</key><integer>3</integer><br>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:          </dict><br>
>>>  // CHECK-NEXT:          <dict><br>
>>> -// CHECK-NEXT:           <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:           <key>line</key><integer>13</integer><br>
>>>  // CHECK-NEXT:           <key>col</key><integer>8</integer><br>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:          </dict><br>
>>> @@ -117,7 +260,7 @@ void test() {<br>
>>>  // CHECK-NEXT:     <key>kind</key><string>event</string><br>
>>>  // CHECK-NEXT:     <key>location</key><br>
>>>  // CHECK-NEXT:     <dict><br>
>>> -// CHECK-NEXT:      <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:      <key>line</key><integer>13</integer><br>
>>>  // CHECK-NEXT:      <key>col</key><integer>3</integer><br>
>>>  // CHECK-NEXT:      <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:     </dict><br>
>>> @@ -125,12 +268,12 @@ void test() {<br>
>>>  // CHECK-NEXT:     <array><br>
>>>  // CHECK-NEXT:       <array><br>
>>>  // CHECK-NEXT:        <dict><br>
>>> -// CHECK-NEXT:         <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:         <key>line</key><integer>13</integer><br>
>>>  // CHECK-NEXT:         <key>col</key><integer>10</integer><br>
>>>  // CHECK-NEXT:         <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:        </dict><br>
>>>  // CHECK-NEXT:        <dict><br>
>>> -// CHECK-NEXT:         <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:         <key>line</key><integer>13</integer><br>
>>>  // CHECK-NEXT:         <key>col</key><integer>10</integer><br>
>>>  // CHECK-NEXT:         <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:        </dict><br>
>>> @@ -152,7 +295,7 @@ void test() {<br>
>>>  // CHECK-NEXT:  <key>issue_hash</key><string>4</string><br>
>>>  // CHECK-NEXT:  <key>location</key><br>
>>>  // CHECK-NEXT:  <dict><br>
>>> -// CHECK-NEXT:   <key>line</key><integer>10</integer><br>
>>> +// CHECK-NEXT:   <key>line</key><integer>13</integer><br>
>>>  // CHECK-NEXT:   <key>col</key><integer>3</integer><br>
>>>  // CHECK-NEXT:   <key>file</key><integer>0</integer><br>
>>>  // CHECK-NEXT:  </dict><br>
>>><br>
>>> Modified: cfe/trunk/test/CodeGenCXX/new.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/new.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/new.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/test/CodeGenCXX/new.cpp (original)<br>
>>> +++ cfe/trunk/test/CodeGenCXX/new.cpp Mon May 18 14:59:11 2015<br>
>>> @@ -321,14 +321,14 @@ namespace N3664 {<br>
>>>    // CHECK-LABEL: define void @_ZN5N36641fEv<br>
>>>    void f() {<br>
>>>      // CHECK: call noalias i8* @_Znwm(i64 4) [[ATTR_BUILTIN_NEW:#[^ ]*]]<br>
>>> -    int *p = new int;<br>
>>> +    int *p = new int; // expected-note {{allocated with 'new' here}}<br>
>>>      // CHECK: call void @_ZdlPv({{.*}}) [[ATTR_BUILTIN_DELETE:#[^ ]*]]<br>
>>>      delete p;<br>
>>><br>
>>>      // CHECK: call noalias i8* @_Znam(i64 12) [[ATTR_BUILTIN_NEW]]<br>
>>>      int *q = new int[3];<br>
>>>      // CHECK: call void @_ZdaPv({{.*}}) [[ATTR_BUILTIN_DELETE]]<br>
>>> -    delete [] p;<br>
>>> +    delete[] p; // expected-warning {{'delete[]' applied to a pointer<br>
>>> that was allocated with 'new'; did you mean 'delete'?}}<br>
>>><br>
>>>      // CHECK: call i8* @_ZnamRKSt9nothrow_t(i64 3, {{.*}})<br>
>>> [[ATTR_BUILTIN_NOTHROW_NEW:#[^ ]*]]<br>
>>>      (void) new (nothrow) S[3];<br>
>>><br>
>>> Added: cfe/trunk/test/SemaCXX/delete-mismatch.h<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/delete-mismatch.h?rev=237608&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/delete-mismatch.h?rev=237608&view=auto</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/test/SemaCXX/delete-mismatch.h (added)<br>
>>> +++ cfe/trunk/test/SemaCXX/delete-mismatch.h Mon May 18 14:59:11 2015<br>
>>> @@ -0,0 +1,15 @@<br>
>>> +// Header for PCH test delete.cpp<br>
>>> +namespace pch_test {<br>
>>> +struct X {<br>
>>> +  int *a;<br>
>>> +  X();<br>
>>> +  X(int);<br>
>>> +  X(bool)<br>
>>> +    : a(new int[1]) { } // expected-note{{allocated with 'new[]' here}}<br>
>>> +  ~X()<br>
>>> +  {<br>
>>> +    delete a; // expected-warning{{'delete' applied to a pointer that was<br>
>>> allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +    // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:9}:"[]"<br>
>>> +  }<br>
>>> +};<br>
>>> +}<br>
>>><br>
>>> Modified: cfe/trunk/test/SemaCXX/delete.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/delete.cpp?rev=237608&r1=237607&r2=237608&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/delete.cpp?rev=237608&r1=237607&r2=237608&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/test/SemaCXX/delete.cpp (original)<br>
>>> +++ cfe/trunk/test/SemaCXX/delete.cpp Mon May 18 14:59:11 2015<br>
>>> @@ -1,9 +1,130 @@<br>
>>> -// RUN: %clang_cc1 -fsyntax-only -verify %s<br>
>>> -// RUN: cp %s %t<br>
>>> -// RUN: %clang_cc1 -fixit -x c++ %t<br>
>>> -// RUN: %clang_cc1 -E -o - %t | FileCheck %s<br>
>>> +// Test without PCH<br>
>>> +// RUN: %clang_cc1 -fsyntax-only -include %S/delete-mismatch.h<br>
>>> -fdiagnostics-parseable-fixits -std=c++11 %s 2>&1 | FileCheck %s<br>
>>> +<br>
>>> +// Test with PCH<br>
>>> +// RUN: %clang_cc1 -x c++-header -std=c++11 -emit-pch -o %t<br>
>>> %S/delete-mismatch.h<br>
>>> +// RUN: %clang_cc1 -std=c++11 -include-pch %t -DWITH_PCH -fsyntax-only<br>
>>> -verify %s -ast-dump<br>
>>><br>
>>>  void f(int a[10][20]) {<br>
>>> -  // CHECK: delete[] a;<br>
>>>    delete a; // expected-warning {{'delete' applied to a pointer-to-array<br>
>>> type}}<br>
>>> +  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:9}:"[]"<br>
>>> +}<br>
>>> +namespace MemberCheck {<br>
>>> +struct S {<br>
>>> +  int *a = new int[5]; // expected-note4 {{allocated with 'new[]' here}}<br>
>>> +  int *b;<br>
>>> +  int *c;<br>
>>> +  static int *d;<br>
>>> +  S();<br>
>>> +  S(int);<br>
>>> +  ~S() {<br>
>>> +    delete a; // expected-warning {{'delete' applied to a pointer that<br>
>>> was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +    delete b;   // expected-warning {{'delete' applied to a pointer that<br>
>>> was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +    delete[] c; // expected-warning {{'delete[]' applied to a pointer<br>
>>> that was allocated with 'new'; did you mean 'delete'?}}<br>
>>> +  }<br>
>>> +  void f();<br>
>>> +};<br>
>>> +<br>
>>> +void S::f()<br>
>>> +{<br>
>>> +  delete a; // expected-warning {{'delete' applied to a pointer that was<br>
>>> allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +  delete b; // expected-warning {{'delete' applied to a pointer that was<br>
>>> allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +}<br>
>>> +<br>
>>> +S::S()<br>
>>> +: b(new int[1]), c(new int) {} // expected-note3 {{allocated with 'new[]'<br>
>>> here}}<br>
>>> +// expected-note@-1 {{allocated with 'new' here}}<br>
>>> +<br>
>>> +S::S(int i)<br>
>>> +: b(new int[i]), c(new int) {} // expected-note3 {{allocated with 'new[]'<br>
>>> here}}<br>
>>> +// expected-note@-1 {{allocated with 'new' here}}<br>
>>> +<br>
>>> +struct S2 : S {<br>
>>> +  ~S2() {<br>
>>> +    delete a; // expected-warning {{'delete' applied to a pointer that<br>
>>> was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +  }<br>
>>> +};<br>
>>> +int *S::d = new int[42]; // expected-note {{allocated with 'new[]' here}}<br>
>>> +void f(S *s) {<br>
>>> +  int *a = new int[1]; // expected-note {{allocated with 'new[]' here}}<br>
>>> +  delete a; // expected-warning {{'delete' applied to a pointer that was<br>
>>> allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +  delete s->a; // expected-warning {{'delete' applied to a pointer that<br>
>>> was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +  delete s->b; // expected-warning {{'delete' applied to a pointer that<br>
>>> was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +  delete s->c;<br>
>>> +  delete s->d;<br>
>>> +  delete S::d; // expected-warning {{'delete' applied to a pointer that<br>
>>> was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +}<br>
>>> +<br>
>>> +// At least one constructor initializes field with matching form of<br>
>>> 'new'.<br>
>>> +struct MatchingNewIsOK {<br>
>>> +  int *p;<br>
>>> +  bool is_array_;<br>
>>> +  MatchingNewIsOK() : p{new int}, is_array_(false) {}<br>
>>> +  explicit MatchingNewIsOK(unsigned c) : p{new int[c]}, is_array_(true)<br>
>>> {}<br>
>>> +  ~MatchingNewIsOK() {<br>
>>> +    if (is_array_)<br>
>>> +      delete[] p;<br>
>>> +    else<br>
>>> +      delete p;<br>
>>> +  }<br>
>>> +};<br>
>>> +<br>
>>> +// At least one constructor's body is missing; no proof of mismatch.<br>
>>> +struct CantProve_MissingCtorDefinition {<br>
>>> +  int *p;<br>
>>> +  CantProve_MissingCtorDefinition();<br>
>>> +  CantProve_MissingCtorDefinition(int);<br>
>>> +  ~CantProve_MissingCtorDefinition();<br>
>>> +};<br>
>>> +<br>
>>> +CantProve_MissingCtorDefinition::CantProve_MissingCtorDefinition()<br>
>>> +  : p(new int)<br>
>>> +{ }<br>
>>> +<br>
>>> +CantProve_MissingCtorDefinition::~CantProve_MissingCtorDefinition()<br>
>>> +{<br>
>>> +  delete[] p;<br>
>>> +}<br>
>>> +<br>
>>> +struct base {};<br>
>>> +struct derived : base {};<br>
>>> +struct InitList {<br>
>>> +  base *p, *p2 = nullptr, *p3{nullptr}, *p4;<br>
>>> +  InitList(unsigned c) : p(new derived[c]), p4(nullptr) {}  //<br>
>>> expected-note {{allocated with 'new[]' here}}<br>
>>> +  InitList(unsigned c, unsigned) : p{new derived[c]}, p4{nullptr} {} //<br>
>>> expected-note {{allocated with 'new[]' here}}<br>
>>> +  ~InitList() {<br>
>>> +    delete p; // expected-warning {{'delete' applied to a pointer that<br>
>>> was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +    delete [] p;<br>
>>> +    delete p2;<br>
>>> +    delete [] p3;<br>
>>> +    delete p4;<br>
>>> +  }<br>
>>> +};<br>
>>> +}<br>
>>> +<br>
>>> +namespace NonMemberCheck {<br>
>>> +#define DELETE_ARRAY(x) delete[] (x)<br>
>>> +#define DELETE(x) delete (x)<br>
>>> +void f() {<br>
>>> +  int *a = new int(5); // expected-note2 {{allocated with 'new' here}}<br>
>>> +  delete[] a;          // expected-warning {{'delete[]' applied to a<br>
>>> pointer that was allocated with 'new'; did you mean 'delete'?}}<br>
>>> +  int *b = new int;<br>
>>> +  delete b;<br>
>>> +  int *c{new int};    // expected-note {{allocated with 'new' here}}<br>
>>> +  int *d{new int[1]}; // expected-note2 {{allocated with 'new[]' here}}<br>
>>> +  delete  [    ] c;   // expected-warning {{'delete[]' applied to a<br>
>>> pointer that was allocated with 'new'; did you mean 'delete'?}}<br>
>>> +  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:17}:""<br>
>>> +  delete d;           // expected-warning {{'delete' applied to a pointer<br>
>>> that was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +  // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:9}:"[]"<br>
>>> +  DELETE_ARRAY(a);    // expected-warning {{'delete[]' applied to a<br>
>>> pointer that was allocated with 'new'; did you mean 'delete'?}}<br>
>>> +  DELETE(d);          // expected-warning {{'delete' applied to a pointer<br>
>>> that was allocated with 'new[]'; did you mean 'delete[]'?}}<br>
>>> +}<br>
>>>  }<br>
>>> +#ifndef WITH_PCH<br>
>>> +pch_test::X::X()<br>
>>> +  : a(new int[1])  // expected-note{{allocated with 'new[]' here}}<br>
>>> +{ }<br>
>>> +pch_test::X::X(int i)<br>
>>> +  : a(new int[i])  // expected-note{{allocated with 'new[]' here}}<br>
>>> +{ }<br>
>>> +#endif<br>
>>><br>
>>><br>
>>> _______________________________________________<br>
>>> cfe-commits mailing list<br>
>>> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
>>> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
>><br>
>><br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</div></div></blockquote></div><br></div></div>