r237608 - Detect uses of mismatching forms of 'new' and 'delete'

Ismail Pazarbasi ismail.pazarbasi at gmail.com
Mon May 18 14:24:25 PDT 2015


On Mon, May 18, 2015 at 11:12 PM, Ismail Pazarbasi
<ismail.pazarbasi at gmail.com> wrote:
> On Mon, May 18, 2015 at 10:57 PM, Richard Smith <richard at metafoo.co.uk> wrote:
>> This has introduced a new warning:
>>
>> include/clang/Serialization/ASTReader.h:1746:8: warning:
>> 'ReadMismatchingDeleteExpressions' overrides a member function but is not
>> marked 'override' [-Winconsistent-missing-override]
>>   void ReadMismatchingDeleteExpressions(llvm::MapVector<
>>        ^
>> include/clang/Sema/ExternalSemaSource.h:83:16: note: overridden virtual
>> function is here
>>   virtual void ReadMismatchingDeleteExpressions(llvm::MapVector<
>>                ^
>>
>> Please can you fix this?
> Yes, already landed in r237613.
I have added LLVM_ENABLE_WERROR to my build config, and currently rebuilding.

Perhaps a cfe-dev discussion, but let me try here first; would it make
sense to set LLVM_ENABLE_WERROR on by default?

>
>>
>> On Mon, May 18, 2015 at 12:59 PM, Ismail Pazarbasi
>> <ismail.pazarbasi at gmail.com> wrote:
>>>
>>> Author: ismailp
>>> Date: Mon May 18 14:59:11 2015
>>> New Revision: 237608
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=237608&view=rev
>>> Log:
>>> Detect uses of mismatching forms of 'new' and 'delete'
>>>
>>> Emit warning when operand to `delete` is allocated with `new[]` or
>>> operand to `delete[]` is allocated with `new`.
>>>
>>> rev 2 update:
>>> `getNewExprFromInitListOrExpr` should return `dyn_cast_or_null`
>>> instead of `dyn_cast`, since `E` might be null.
>>>
>>> Reviewers: rtrieu, jordan_rose, rsmith
>>>
>>> Subscribers: majnemer, cfe-commits
>>>
>>> Differential Revision: http://reviews.llvm.org/D4661
>>>
>>> Added:
>>>     cfe/trunk/test/SemaCXX/delete-mismatch.h
>>> Modified:
>>>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>>     cfe/trunk/include/clang/Sema/ExternalSemaSource.h
>>>     cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h
>>>     cfe/trunk/include/clang/Sema/Sema.h
>>>     cfe/trunk/include/clang/Serialization/ASTBitCodes.h
>>>     cfe/trunk/include/clang/Serialization/ASTReader.h
>>>     cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp
>>>     cfe/trunk/lib/Sema/Sema.cpp
>>>     cfe/trunk/lib/Sema/SemaExprCXX.cpp
>>>     cfe/trunk/lib/Serialization/ASTReader.cpp
>>>     cfe/trunk/lib/Serialization/ASTWriter.cpp
>>>     cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
>>>     cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm
>>>     cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp
>>>     cfe/trunk/test/CodeGenCXX/new.cpp
>>>     cfe/trunk/test/SemaCXX/delete.cpp
>>>
>>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon May 18
>>> 14:59:11 2015
>>> @@ -5516,7 +5516,12 @@ def err_delete_explicit_conversion : Err
>>>    "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[]">;
>>> +  "'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<DiagGroup<"mismatched-new-delete">>;
>>> +def note_allocated_here : Note<"allocated with 'new%select{[]|}0' here">;
>>>  def err_no_suitable_delete_member_function_found : Error<
>>>    "no suitable member %0 in %1">;
>>>  def err_ambiguous_suitable_delete_member_function_found : Error<
>>>
>>> Modified: cfe/trunk/include/clang/Sema/ExternalSemaSource.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/ExternalSemaSource.h?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Sema/ExternalSemaSource.h (original)
>>> +++ cfe/trunk/include/clang/Sema/ExternalSemaSource.h Mon May 18 14:59:11
>>> 2015
>>> @@ -27,6 +27,7 @@ template <class T, unsigned n> class Sma
>>>  namespace clang {
>>>
>>>  class CXXConstructorDecl;
>>> +class CXXDeleteExpr;
>>>  class CXXRecordDecl;
>>>  class DeclaratorDecl;
>>>  class LookupResult;
>>> @@ -79,6 +80,9 @@ public:
>>>    virtual void ReadUndefinedButUsed(
>>>                           llvm::DenseMap<NamedDecl*, SourceLocation>
>>> &Undefined);
>>>
>>> +  virtual void ReadMismatchingDeleteExpressions(llvm::MapVector<
>>> +      FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>>
>>> &);
>>> +
>>>    /// \brief Do last resort, unqualified lookup on a LookupResult that
>>>    /// Sema cannot find.
>>>    ///
>>>
>>> Modified: cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h (original)
>>> +++ cfe/trunk/include/clang/Sema/MultiplexExternalSemaSource.h Mon May 18
>>> 14:59:11 2015
>>> @@ -230,6 +230,10 @@ public:
>>>    void ReadUndefinedButUsed(
>>>                  llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined)
>>> override;
>>>
>>> +  void ReadMismatchingDeleteExpressions(llvm::MapVector<
>>> +      FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>>
>>> &
>>> +                                            Exprs) override;
>>> +
>>>    /// \brief Do last resort, unqualified lookup on a LookupResult that
>>>    /// Sema cannot find.
>>>    ///
>>>
>>> Modified: cfe/trunk/include/clang/Sema/Sema.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Sema/Sema.h (original)
>>> +++ cfe/trunk/include/clang/Sema/Sema.h Mon May 18 14:59:11 2015
>>> @@ -78,6 +78,7 @@ namespace clang {
>>>    typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
>>>    class CXXConstructorDecl;
>>>    class CXXConversionDecl;
>>> +  class CXXDeleteExpr;
>>>    class CXXDestructorDecl;
>>>    class CXXFieldCollector;
>>>    class CXXMemberCallExpr;
>>> @@ -404,6 +405,15 @@ public:
>>>    llvm::SmallSetVector<const TypedefNameDecl *, 4>
>>>        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<SourceLocation, bool> DeleteExprLoc;
>>> +  typedef llvm::SmallVector<DeleteExprLoc, 4> DeleteLocs;
>>> +  llvm::MapVector<FieldDecl *, DeleteLocs> DeleteExprs;
>>> +
>>>    typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy;
>>>
>>>    /// PureVirtualClassDiagSet - a set of class declarations which we have
>>> @@ -888,6 +898,11 @@ public:
>>>    void getUndefinedButUsed(
>>>        SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >
>>> &Undefined);
>>>
>>> +  /// Retrieves list of suspicious delete-expressions that will be
>>> checked at
>>> +  /// the end of translation unit.
>>> +  const llvm::MapVector<FieldDecl *, DeleteLocs> &
>>> +  getMismatchingDeleteExpressions() const;
>>> +
>>>    typedef std::pair<ObjCMethodList, ObjCMethodList> GlobalMethods;
>>>    typedef llvm::DenseMap<Selector, GlobalMethods> GlobalMethodPool;
>>>
>>> @@ -8663,6 +8678,9 @@ 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,
>>>
>>> Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
>>> +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Mon May 18
>>> 14:59:11 2015
>>> @@ -561,6 +561,9 @@ 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.
>>>
>>> Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
>>> +++ cfe/trunk/include/clang/Serialization/ASTReader.h Mon May 18 14:59:11
>>> 2015
>>> @@ -760,6 +760,9 @@ private:
>>>    /// SourceLocation of a matching ODR-use.
>>>    SmallVector<uint64_t, 8> UndefinedButUsed;
>>>
>>> +  /// \brief Delete expressions to analyze at the end of translation
>>> unit.
>>> +  SmallVector<uint64_t, 8> DelayedDeleteExprs;
>>> +
>>>    // \brief A list of late parsed template function data.
>>>    SmallVector<uint64_t, 1> LateParsedTemplates;
>>>
>>> @@ -1740,6 +1743,10 @@ public:
>>>    void ReadUndefinedButUsed(
>>>                 llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined)
>>> override;
>>>
>>> +  void ReadMismatchingDeleteExpressions(llvm::MapVector<
>>> +      FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>>
>>> &
>>> +                                            Exprs);
>>> +
>>>    void ReadTentativeDefinitions(
>>>                              SmallVectorImpl<VarDecl *> &TentativeDefs)
>>> override;
>>>
>>>
>>> Modified: cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp (original)
>>> +++ cfe/trunk/lib/Sema/MultiplexExternalSemaSource.cpp Mon May 18 14:59:11
>>> 2015
>>> @@ -212,7 +212,15 @@ void MultiplexExternalSemaSource::ReadUn
>>>    for(size_t i = 0; i < Sources.size(); ++i)
>>>      Sources[i]->ReadUndefinedButUsed(Undefined);
>>>  }
>>> -
>>> +
>>> +void MultiplexExternalSemaSource::ReadMismatchingDeleteExpressions(
>>> +    llvm::MapVector<FieldDecl *,
>>> +                    llvm::SmallVector<std::pair<SourceLocation, bool>,
>>> 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);
>>>
>>> Modified: cfe/trunk/lib/Sema/Sema.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Sema/Sema.cpp (original)
>>> +++ cfe/trunk/lib/Sema/Sema.cpp Mon May 18 14:59:11 2015
>>> @@ -861,6 +861,17 @@ 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.
>>> @@ -1220,6 +1231,9 @@ void ExternalSemaSource::ReadUndefinedBu
>>>                         llvm::DenseMap<NamedDecl *, SourceLocation>
>>> &Undefined) {
>>>  }
>>>
>>> +void
>>> ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector<
>>> +    FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>>
>>> &) {}
>>> +
>>>  void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const {
>>>    SourceLocation Loc = this->Loc;
>>>    if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation();
>>> @@ -1468,3 +1482,8 @@ CapturedRegionScopeInfo *Sema::getCurCap
>>>
>>>    return dyn_cast<CapturedRegionScopeInfo>(FunctionScopes.back());
>>>  }
>>> +
>>> +const llvm::MapVector<FieldDecl *, Sema::DeleteLocs> &
>>> +Sema::getMismatchingDeleteExpressions() const {
>>> +  return DeleteExprs;
>>> +}
>>>
>>> Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
>>> +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon May 18 14:59:11 2015
>>> @@ -2339,6 +2339,261 @@ bool Sema::FindDeallocationFunction(Sour
>>>    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<const CXXNewExpr *, 4> 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<const MemberExpr>(E)) {
>>> +    return analyzeMemberExpr(ME);
>>> +  } else if (const DeclRefExpr *D = dyn_cast<const DeclRefExpr>(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<const InitListExpr>(E)) {
>>> +    if (ILE->getNumInits() == 1)
>>> +      E = dyn_cast<const
>>> CXXNewExpr>(ILE->getInit(0)->IgnoreParenImpCasts());
>>> +  }
>>> +
>>> +  return dyn_cast_or_null<const CXXNewExpr>(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<const
>>> CXXConstructorDecl>(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<const
>>> CXXRecordDecl>(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<FieldDecl>(ME->getMemberDecl()))
>>> +    return analyzeField(F, IsArrayForm);
>>> +  return NoMismatch;
>>> +}
>>> +
>>> +bool MismatchingNewDeleteDetector::hasMatchingVarInit(const DeclRefExpr
>>> *D) {
>>> +  const CXXNewExpr *NE = nullptr;
>>> +  if (const VarDecl *VD = dyn_cast<const VarDecl>(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
>>> @@ -2454,12 +2709,6 @@ Sema::ActOnCXXDelete(SourceLocation Star
>>>        }
>>>      }
>>>
>>> -    // 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()
>>> @@ -2534,7 +2783,7 @@ Sema::ActOnCXXDelete(SourceLocation Star
>>>            DeleteName);
>>>
>>>      MarkFunctionReferenced(StartLoc, OperatorDelete);
>>> -
>>> +
>>>      // Check access and ambiguity of operator delete and destructor.
>>>      if (PointeeRD) {
>>>        if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
>>> @@ -2544,9 +2793,11 @@ Sema::ActOnCXXDelete(SourceLocation Star
>>>      }
>>>    }
>>>
>>> -  return new (Context) CXXDeleteExpr(
>>> +  CXXDeleteExpr *Result = 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,
>>>
>>> Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
>>> +++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon May 18 14:59:11 2015
>>> @@ -3021,6 +3021,18 @@ ASTReader::ReadASTBlock(ModuleFile &F, u
>>>              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) {
>>> @@ -7016,6 +7028,21 @@ void ASTReader::ReadUndefinedButUsed(
>>>    }
>>>  }
>>>
>>> +void ASTReader::ReadMismatchingDeleteExpressions(llvm::MapVector<
>>> +    FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &
>>> +                                                     Exprs) {
>>> +  for (unsigned Idx = 0, N = DelayedDeleteExprs.size(); Idx != N;) {
>>> +    FieldDecl *FD = cast<FieldDecl>(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<VarDecl *> &TentativeDefs) {
>>>    for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
>>>
>>> Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
>>> +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon May 18 14:59:11 2015
>>> @@ -4155,6 +4155,20 @@ void ASTWriter::WriteASTCore(Sema &SemaR
>>>      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);
>>>
>>> @@ -4424,7 +4438,10 @@ void ASTWriter::WriteASTCore(Sema &SemaR
>>>    // 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);
>>>
>>> Modified:
>>> cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/Malloc%2BMismatchedDeallocator%2BNewDelete.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
>>> (original)
>>> +++ cfe/trunk/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp Mon
>>> May 18 14:59:11 2015
>>> @@ -97,9 +97,11 @@ void testShouldReportDoubleFreeNotMismat
>>>    free(p);
>>>    delete globalPtr; // expected-warning {{Attempt to free released
>>> memory}}
>>>  }
>>> -
>>> +int *allocIntArray(unsigned c) {
>>> +  return new int[c];
>>> +}
>>>  void testMismatchedChangePointeeThroughAssignment() {
>>> -  int *arr = new int[4];
>>> +  int *arr = allocIntArray(4);
>>>    globalPtr = arr;
>>>    delete arr; // expected-warning{{Memory allocated by 'new[]' should be
>>> deallocated by 'delete[]', not 'delete'}}
>>> -}
>>> \ No newline at end of file
>>> +}
>>>
>>> Modified: cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm
>>> (original)
>>> +++ cfe/trunk/test/Analysis/MismatchedDeallocator-checker-test.mm Mon May
>>> 18 14:59:11 2015
>>> @@ -95,8 +95,11 @@ 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 = new int;
>>> +  int *p = allocInt();
>>>    delete[] p; // expected-warning{{Memory allocated by 'new' should be
>>> deallocated by 'delete', not 'delete[]'}}
>>>  }
>>>
>>> @@ -105,8 +108,12 @@ 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 = new int[1];
>>> +  int *p = allocIntArray(1);
>>>    delete p; // expected-warning{{Memory allocated by 'new[]' should be
>>> deallocated by 'delete[]', not 'delete'}}
>>>  }
>>>
>>>
>>> Modified: cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp
>>> (original)
>>> +++ cfe/trunk/test/Analysis/MismatchedDeallocator-path-notes.cpp Mon May
>>> 18 14:59:11 2015
>>> @@ -3,9 +3,12 @@
>>>  // 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 = new int[1];
>>> -  // expected-note at -1 {{Memory is allocated}}
>>> +  int *p = allocIntArray(1); // expected-note {{Calling 'allocIntArray'}}
>>> +  // expected-note at -1 {{Returned allocated memory}}
>>>    changePointee(p);
>>>    delete p; // expected-warning {{Memory allocated by 'new[]' should be
>>> deallocated by 'delete[]', not 'delete'}}
>>>    // expected-note at -1 {{Memory allocated by 'new[]' should be deallocated
>>> by 'delete[]', not 'delete'}}
>>> @@ -24,13 +27,124 @@ void test() {
>>>  // CHECK-NEXT:        <key>start</key>
>>>  // CHECK-NEXT:         <array>
>>>  // CHECK-NEXT:          <dict>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>3</integer>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:          </dict>
>>> +// CHECK-NEXT:          <dict>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>5</integer>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:          </dict>
>>> +// CHECK-NEXT:         </array>
>>> +// CHECK-NEXT:        <key>end</key>
>>> +// CHECK-NEXT:         <array>
>>> +// CHECK-NEXT:          <dict>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>12</integer>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:          </dict>
>>> +// CHECK-NEXT:          <dict>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>24</integer>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:          </dict>
>>> +// CHECK-NEXT:         </array>
>>> +// CHECK-NEXT:       </dict>
>>> +// CHECK-NEXT:      </array>
>>> +// CHECK-NEXT:    </dict>
>>> +// CHECK-NEXT:    <dict>
>>> +// CHECK-NEXT:     <key>kind</key><string>event</string>
>>> +// CHECK-NEXT:     <key>location</key>
>>> +// CHECK-NEXT:     <dict>
>>> +// CHECK-NEXT:      <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:      <key>col</key><integer>12</integer>
>>> +// CHECK-NEXT:      <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:     </dict>
>>> +// CHECK-NEXT:     <key>ranges</key>
>>> +// CHECK-NEXT:     <array>
>>> +// CHECK-NEXT:       <array>
>>> +// CHECK-NEXT:        <dict>
>>> +// CHECK-NEXT:         <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:         <key>col</key><integer>12</integer>
>>> +// CHECK-NEXT:         <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:        </dict>
>>> +// CHECK-NEXT:        <dict>
>>> +// CHECK-NEXT:         <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:         <key>col</key><integer>27</integer>
>>> +// CHECK-NEXT:         <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:        </dict>
>>> +// CHECK-NEXT:       </array>
>>> +// CHECK-NEXT:     </array>
>>> +// CHECK-NEXT:     <key>depth</key><integer>0</integer>
>>> +// CHECK-NEXT:     <key>extended_message</key>
>>> +// CHECK-NEXT:     <string>Calling 'allocIntArray'</string>
>>> +// CHECK-NEXT:     <key>message</key>
>>> +// CHECK-NEXT:     <string>Calling 'allocIntArray'</string>
>>> +// CHECK-NEXT:    </dict>
>>> +// CHECK-NEXT:    <dict>
>>> +// CHECK-NEXT:     <key>kind</key><string>event</string>
>>> +// CHECK-NEXT:     <key>location</key>
>>> +// CHECK-NEXT:     <dict>
>>> +// CHECK-NEXT:      <key>line</key><integer>6</integer>
>>> +// CHECK-NEXT:      <key>col</key><integer>1</integer>
>>> +// CHECK-NEXT:      <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:     </dict>
>>> +// CHECK-NEXT:     <key>depth</key><integer>1</integer>
>>> +// CHECK-NEXT:     <key>extended_message</key>
>>> +// CHECK-NEXT:     <string>Entered call from 'test'</string>
>>> +// CHECK-NEXT:     <key>message</key>
>>> +// CHECK-NEXT:     <string>Entered call from 'test'</string>
>>> +// CHECK-NEXT:    </dict>
>>> +// CHECK-NEXT:    <dict>
>>> +// CHECK-NEXT:     <key>kind</key><string>control</string>
>>> +// CHECK-NEXT:     <key>edges</key>
>>> +// CHECK-NEXT:      <array>
>>> +// CHECK-NEXT:       <dict>
>>> +// CHECK-NEXT:        <key>start</key>
>>> +// CHECK-NEXT:         <array>
>>> +// CHECK-NEXT:          <dict>
>>> +// CHECK-NEXT:           <key>line</key><integer>6</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>1</integer>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:          </dict>
>>> +// CHECK-NEXT:          <dict>
>>> +// CHECK-NEXT:           <key>line</key><integer>6</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>3</integer>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:          </dict>
>>> +// CHECK-NEXT:         </array>
>>> +// CHECK-NEXT:        <key>end</key>
>>> +// CHECK-NEXT:         <array>
>>> +// CHECK-NEXT:          <dict>
>>>  // CHECK-NEXT:           <key>line</key><integer>7</integer>
>>>  // CHECK-NEXT:           <key>col</key><integer>3</integer>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:          </dict>
>>>  // CHECK-NEXT:          <dict>
>>>  // CHECK-NEXT:           <key>line</key><integer>7</integer>
>>> -// CHECK-NEXT:           <key>col</key><integer>5</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>8</integer>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:          </dict>
>>> +// CHECK-NEXT:         </array>
>>> +// CHECK-NEXT:       </dict>
>>> +// CHECK-NEXT:      </array>
>>> +// CHECK-NEXT:    </dict>
>>> +// CHECK-NEXT:    <dict>
>>> +// CHECK-NEXT:     <key>kind</key><string>control</string>
>>> +// CHECK-NEXT:     <key>edges</key>
>>> +// CHECK-NEXT:      <array>
>>> +// CHECK-NEXT:       <dict>
>>> +// CHECK-NEXT:        <key>start</key>
>>> +// CHECK-NEXT:         <array>
>>> +// CHECK-NEXT:          <dict>
>>> +// CHECK-NEXT:           <key>line</key><integer>7</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>3</integer>
>>> +// CHECK-NEXT:           <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:          </dict>
>>> +// CHECK-NEXT:          <dict>
>>> +// CHECK-NEXT:           <key>line</key><integer>7</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>8</integer>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:          </dict>
>>>  // CHECK-NEXT:         </array>
>>> @@ -38,12 +152,12 @@ void test() {
>>>  // CHECK-NEXT:         <array>
>>>  // CHECK-NEXT:          <dict>
>>>  // CHECK-NEXT:           <key>line</key><integer>7</integer>
>>> -// CHECK-NEXT:           <key>col</key><integer>12</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>10</integer>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:          </dict>
>>>  // CHECK-NEXT:          <dict>
>>>  // CHECK-NEXT:           <key>line</key><integer>7</integer>
>>> -// CHECK-NEXT:           <key>col</key><integer>14</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>12</integer>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:          </dict>
>>>  // CHECK-NEXT:         </array>
>>> @@ -55,7 +169,7 @@ void test() {
>>>  // CHECK-NEXT:     <key>location</key>
>>>  // CHECK-NEXT:     <dict>
>>>  // CHECK-NEXT:      <key>line</key><integer>7</integer>
>>> -// CHECK-NEXT:      <key>col</key><integer>12</integer>
>>> +// CHECK-NEXT:      <key>col</key><integer>10</integer>
>>>  // CHECK-NEXT:      <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:     </dict>
>>>  // CHECK-NEXT:     <key>ranges</key>
>>> @@ -63,23 +177,52 @@ void test() {
>>>  // CHECK-NEXT:       <array>
>>>  // CHECK-NEXT:        <dict>
>>>  // CHECK-NEXT:         <key>line</key><integer>7</integer>
>>> -// CHECK-NEXT:         <key>col</key><integer>12</integer>
>>> +// CHECK-NEXT:         <key>col</key><integer>10</integer>
>>>  // CHECK-NEXT:         <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:        </dict>
>>>  // CHECK-NEXT:        <dict>
>>>  // CHECK-NEXT:         <key>line</key><integer>7</integer>
>>> -// CHECK-NEXT:         <key>col</key><integer>21</integer>
>>> +// CHECK-NEXT:         <key>col</key><integer>19</integer>
>>>  // CHECK-NEXT:         <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:        </dict>
>>>  // CHECK-NEXT:       </array>
>>>  // CHECK-NEXT:     </array>
>>> -// CHECK-NEXT:     <key>depth</key><integer>0</integer>
>>> +// CHECK-NEXT:     <key>depth</key><integer>1</integer>
>>>  // CHECK-NEXT:     <key>extended_message</key>
>>>  // CHECK-NEXT:     <string>Memory is allocated</string>
>>>  // CHECK-NEXT:     <key>message</key>
>>>  // CHECK-NEXT:     <string>Memory is allocated</string>
>>>  // CHECK-NEXT:    </dict>
>>>  // CHECK-NEXT:    <dict>
>>> +// CHECK-NEXT:     <key>kind</key><string>event</string>
>>> +// CHECK-NEXT:     <key>location</key>
>>> +// CHECK-NEXT:     <dict>
>>> +// CHECK-NEXT:      <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:      <key>col</key><integer>12</integer>
>>> +// CHECK-NEXT:      <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:     </dict>
>>> +// CHECK-NEXT:     <key>ranges</key>
>>> +// CHECK-NEXT:     <array>
>>> +// CHECK-NEXT:       <array>
>>> +// CHECK-NEXT:        <dict>
>>> +// CHECK-NEXT:         <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:         <key>col</key><integer>12</integer>
>>> +// CHECK-NEXT:         <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:        </dict>
>>> +// CHECK-NEXT:        <dict>
>>> +// CHECK-NEXT:         <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:         <key>col</key><integer>27</integer>
>>> +// CHECK-NEXT:         <key>file</key><integer>0</integer>
>>> +// CHECK-NEXT:        </dict>
>>> +// CHECK-NEXT:       </array>
>>> +// CHECK-NEXT:     </array>
>>> +// CHECK-NEXT:     <key>depth</key><integer>0</integer>
>>> +// CHECK-NEXT:     <key>extended_message</key>
>>> +// CHECK-NEXT:     <string>Returned allocated memory</string>
>>> +// CHECK-NEXT:     <key>message</key>
>>> +// CHECK-NEXT:     <string>Returned allocated memory</string>
>>> +// CHECK-NEXT:    </dict>
>>> +// CHECK-NEXT:    <dict>
>>>  // CHECK-NEXT:     <key>kind</key><string>control</string>
>>>  // CHECK-NEXT:     <key>edges</key>
>>>  // CHECK-NEXT:      <array>
>>> @@ -87,25 +230,25 @@ void test() {
>>>  // CHECK-NEXT:        <key>start</key>
>>>  // CHECK-NEXT:         <array>
>>>  // CHECK-NEXT:          <dict>
>>> -// CHECK-NEXT:           <key>line</key><integer>7</integer>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer>
>>>  // CHECK-NEXT:           <key>col</key><integer>12</integer>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:          </dict>
>>>  // CHECK-NEXT:          <dict>
>>> -// CHECK-NEXT:           <key>line</key><integer>7</integer>
>>> -// CHECK-NEXT:           <key>col</key><integer>14</integer>
>>> +// CHECK-NEXT:           <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:           <key>col</key><integer>24</integer>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:          </dict>
>>>  // CHECK-NEXT:         </array>
>>>  // CHECK-NEXT:        <key>end</key>
>>>  // CHECK-NEXT:         <array>
>>>  // CHECK-NEXT:          <dict>
>>> -// CHECK-NEXT:           <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:           <key>line</key><integer>13</integer>
>>>  // CHECK-NEXT:           <key>col</key><integer>3</integer>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:          </dict>
>>>  // CHECK-NEXT:          <dict>
>>> -// CHECK-NEXT:           <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:           <key>line</key><integer>13</integer>
>>>  // CHECK-NEXT:           <key>col</key><integer>8</integer>
>>>  // CHECK-NEXT:           <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:          </dict>
>>> @@ -117,7 +260,7 @@ void test() {
>>>  // CHECK-NEXT:     <key>kind</key><string>event</string>
>>>  // CHECK-NEXT:     <key>location</key>
>>>  // CHECK-NEXT:     <dict>
>>> -// CHECK-NEXT:      <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:      <key>line</key><integer>13</integer>
>>>  // CHECK-NEXT:      <key>col</key><integer>3</integer>
>>>  // CHECK-NEXT:      <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:     </dict>
>>> @@ -125,12 +268,12 @@ void test() {
>>>  // CHECK-NEXT:     <array>
>>>  // CHECK-NEXT:       <array>
>>>  // CHECK-NEXT:        <dict>
>>> -// CHECK-NEXT:         <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:         <key>line</key><integer>13</integer>
>>>  // CHECK-NEXT:         <key>col</key><integer>10</integer>
>>>  // CHECK-NEXT:         <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:        </dict>
>>>  // CHECK-NEXT:        <dict>
>>> -// CHECK-NEXT:         <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:         <key>line</key><integer>13</integer>
>>>  // CHECK-NEXT:         <key>col</key><integer>10</integer>
>>>  // CHECK-NEXT:         <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:        </dict>
>>> @@ -152,7 +295,7 @@ void test() {
>>>  // CHECK-NEXT:  <key>issue_hash</key><string>4</string>
>>>  // CHECK-NEXT:  <key>location</key>
>>>  // CHECK-NEXT:  <dict>
>>> -// CHECK-NEXT:   <key>line</key><integer>10</integer>
>>> +// CHECK-NEXT:   <key>line</key><integer>13</integer>
>>>  // CHECK-NEXT:   <key>col</key><integer>3</integer>
>>>  // CHECK-NEXT:   <key>file</key><integer>0</integer>
>>>  // CHECK-NEXT:  </dict>
>>>
>>> Modified: cfe/trunk/test/CodeGenCXX/new.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/new.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/CodeGenCXX/new.cpp (original)
>>> +++ cfe/trunk/test/CodeGenCXX/new.cpp Mon May 18 14:59:11 2015
>>> @@ -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;
>>> +    int *p = new int; // expected-note {{allocated with 'new' here}}
>>>      // 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;
>>> +    delete[] p; // expected-warning {{'delete[]' applied to a pointer
>>> that was allocated with 'new'; did you mean 'delete'?}}
>>>
>>>      // CHECK: call i8* @_ZnamRKSt9nothrow_t(i64 3, {{.*}})
>>> [[ATTR_BUILTIN_NOTHROW_NEW:#[^ ]*]]
>>>      (void) new (nothrow) S[3];
>>>
>>> Added: cfe/trunk/test/SemaCXX/delete-mismatch.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/delete-mismatch.h?rev=237608&view=auto
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/SemaCXX/delete-mismatch.h (added)
>>> +++ cfe/trunk/test/SemaCXX/delete-mismatch.h Mon May 18 14:59:11 2015
>>> @@ -0,0 +1,15 @@
>>> +// 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}:"[]"
>>> +  }
>>> +};
>>> +}
>>>
>>> Modified: cfe/trunk/test/SemaCXX/delete.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/delete.cpp?rev=237608&r1=237607&r2=237608&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/SemaCXX/delete.cpp (original)
>>> +++ cfe/trunk/test/SemaCXX/delete.cpp Mon May 18 14:59:11 2015
>>> @@ -1,9 +1,130 @@
>>> -// 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
>>> +// 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
>>>
>>>  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 at -1 {{allocated with 'new' here}}
>>> +
>>> +S::S(int i)
>>> +: b(new int[i]), c(new int) {} // expected-note3 {{allocated with 'new[]'
>>> here}}
>>> +// expected-note at -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, *p2 = nullptr, *p3{nullptr}, *p4;
>>> +  InitList(unsigned c) : p(new derived[c]), p4(nullptr) {}  //
>>> expected-note {{allocated with 'new[]' here}}
>>> +  InitList(unsigned c, unsigned) : p{new derived[c]}, p4{nullptr} {} //
>>> 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;
>>> +    delete p2;
>>> +    delete [] p3;
>>> +    delete p4;
>>> +  }
>>> +};
>>> +}
>>> +
>>> +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
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at cs.uiuc.edu
>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>>



More information about the cfe-commits mailing list