diff options
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
| -rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 623 | 
1 files changed, 482 insertions, 141 deletions
| diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index a92b7ac472e7..7e305ffa8edc 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -113,6 +113,9 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,    bool isDependent = false;    bool LookInScope = false; +  if (SS.isInvalid()) +    return ParsedType(); +    // If we have an object type, it's because we are in a    // pseudo-destructor-expression or a member access expression, and    // we know what type we're looking for. @@ -644,37 +647,98 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,      Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";    if (Ex && !Ex->isTypeDependent()) { -    ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope); -    if (ExRes.isInvalid()) +    QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType()); +    if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex))        return ExprError(); -    Ex = ExRes.get(); + +    // Initialize the exception result.  This implicitly weeds out +    // abstract types or types with inaccessible copy constructors. + +    // C++0x [class.copymove]p31: +    //   When certain criteria are met, an implementation is allowed to omit the +    //   copy/move construction of a class object [...] +    // +    //     - in a throw-expression, when the operand is the name of a +    //       non-volatile automatic object (other than a function or +    //       catch-clause +    //       parameter) whose scope does not extend beyond the end of the +    //       innermost enclosing try-block (if there is one), the copy/move +    //       operation from the operand to the exception object (15.1) can be +    //       omitted by constructing the automatic object directly into the +    //       exception object +    const VarDecl *NRVOVariable = nullptr; +    if (IsThrownVarInScope) +      NRVOVariable = getCopyElisionCandidate(QualType(), Ex, false); + +    InitializedEntity Entity = InitializedEntity::InitializeException( +        OpLoc, ExceptionObjectTy, +        /*NRVO=*/NRVOVariable != nullptr); +    ExprResult Res = PerformMoveOrCopyInitialization( +        Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope); +    if (Res.isInvalid()) +      return ExprError(); +    Ex = Res.get();    } -   +    return new (Context)        CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope);  } -/// CheckCXXThrowOperand - Validate the operand of a throw. -ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, -                                      bool IsThrownVarInScope) { -  // C++ [except.throw]p3: -  //   A throw-expression initializes a temporary object, called the exception -  //   object, the type of which is determined by removing any top-level -  //   cv-qualifiers from the static type of the operand of throw and adjusting -  //   the type from "array of T" or "function returning T" to "pointer to T" -  //   or "pointer to function returning T", [...] -  if (E->getType().hasQualifiers()) -    E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, -                          E->getValueKind()).get(); - -  ExprResult Res = DefaultFunctionArrayConversion(E); -  if (Res.isInvalid()) -    return ExprError(); -  E = Res.get(); +static void +collectPublicBases(CXXRecordDecl *RD, +                   llvm::DenseMap<CXXRecordDecl *, unsigned> &SubobjectsSeen, +                   llvm::SmallPtrSetImpl<CXXRecordDecl *> &VBases, +                   llvm::SetVector<CXXRecordDecl *> &PublicSubobjectsSeen, +                   bool ParentIsPublic) { +  for (const CXXBaseSpecifier &BS : RD->bases()) { +    CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); +    bool NewSubobject; +    // Virtual bases constitute the same subobject.  Non-virtual bases are +    // always distinct subobjects. +    if (BS.isVirtual()) +      NewSubobject = VBases.insert(BaseDecl).second; +    else +      NewSubobject = true; + +    if (NewSubobject) +      ++SubobjectsSeen[BaseDecl]; + +    // Only add subobjects which have public access throughout the entire chain. +    bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public; +    if (PublicPath) +      PublicSubobjectsSeen.insert(BaseDecl); + +    // Recurse on to each base subobject. +    collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen, +                       PublicPath); +  } +} + +static void getUnambiguousPublicSubobjects( +    CXXRecordDecl *RD, llvm::SmallVectorImpl<CXXRecordDecl *> &Objects) { +  llvm::DenseMap<CXXRecordDecl *, unsigned> SubobjectsSeen; +  llvm::SmallSet<CXXRecordDecl *, 2> VBases; +  llvm::SetVector<CXXRecordDecl *> PublicSubobjectsSeen; +  SubobjectsSeen[RD] = 1; +  PublicSubobjectsSeen.insert(RD); +  collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen, +                     /*ParentIsPublic=*/true); + +  for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) { +    // Skip ambiguous objects. +    if (SubobjectsSeen[PublicSubobject] > 1) +      continue; +    Objects.push_back(PublicSubobject); +  } +} + +/// CheckCXXThrowOperand - Validate the operand of a throw. +bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, +                                QualType ExceptionObjectTy, Expr *E) {    //   If the type of the exception would be an incomplete type or a pointer    //   to an incomplete type other than (cv) void the program is ill-formed. -  QualType Ty = E->getType(); +  QualType Ty = ExceptionObjectTy;    bool isPointer = false;    if (const PointerType* Ptr = Ty->getAs<PointerType>()) {      Ty = Ptr->getPointeeType(); @@ -682,49 +746,20 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,    }    if (!isPointer || !Ty->isVoidType()) {      if (RequireCompleteType(ThrowLoc, Ty, -                            isPointer? diag::err_throw_incomplete_ptr -                                     : diag::err_throw_incomplete, +                            isPointer ? diag::err_throw_incomplete_ptr +                                      : diag::err_throw_incomplete,                              E->getSourceRange())) -      return ExprError(); +      return true; -    if (RequireNonAbstractType(ThrowLoc, E->getType(), +    if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy,                                 diag::err_throw_abstract_type, E)) -      return ExprError(); +      return true;    } -  // Initialize the exception result.  This implicitly weeds out -  // abstract types or types with inaccessible copy constructors. -   -  // C++0x [class.copymove]p31: -  //   When certain criteria are met, an implementation is allowed to omit the  -  //   copy/move construction of a class object [...] -  // -  //     - in a throw-expression, when the operand is the name of a  -  //       non-volatile automatic object (other than a function or catch-clause  -  //       parameter) whose scope does not extend beyond the end of the  -  //       innermost enclosing try-block (if there is one), the copy/move  -  //       operation from the operand to the exception object (15.1) can be  -  //       omitted by constructing the automatic object directly into the  -  //       exception object -  const VarDecl *NRVOVariable = nullptr; -  if (IsThrownVarInScope) -    NRVOVariable = getCopyElisionCandidate(QualType(), E, false); - -  InitializedEntity Entity = -      InitializedEntity::InitializeException(ThrowLoc, E->getType(), -                                             /*NRVO=*/NRVOVariable != nullptr); -  Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, -                                        QualType(), E, -                                        IsThrownVarInScope); -  if (Res.isInvalid()) -    return ExprError(); -  E = Res.get(); -    // If the exception has class type, we need additional handling. -  const RecordType *RecordTy = Ty->getAs<RecordType>(); -  if (!RecordTy) -    return E; -  CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); +  CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); +  if (!RD) +    return false;    // If we are throwing a polymorphic class type or pointer thereof,    // exception handling will make use of the vtable. @@ -732,22 +767,69 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,    // If a pointer is thrown, the referenced object will not be destroyed.    if (isPointer) -    return E; +    return false;    // If the class has a destructor, we must be able to call it. -  if (RD->hasIrrelevantDestructor()) -    return E; +  if (!RD->hasIrrelevantDestructor()) { +    if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { +      MarkFunctionReferenced(E->getExprLoc(), Destructor); +      CheckDestructorAccess(E->getExprLoc(), Destructor, +                            PDiag(diag::err_access_dtor_exception) << Ty); +      if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) +        return true; +    } +  } -  CXXDestructorDecl *Destructor = LookupDestructor(RD); -  if (!Destructor) -    return E; +  // The MSVC ABI creates a list of all types which can catch the exception +  // object.  This list also references the appropriate copy constructor to call +  // if the object is caught by value and has a non-trivial copy constructor. +  if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { +    // We are only interested in the public, unambiguous bases contained within +    // the exception object.  Bases which are ambiguous or otherwise +    // inaccessible are not catchable types. +    llvm::SmallVector<CXXRecordDecl *, 2> UnambiguousPublicSubobjects; +    getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects); + +    for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) { +      // Attempt to lookup the copy constructor.  Various pieces of machinery +      // will spring into action, like template instantiation, which means this +      // cannot be a simple walk of the class's decls.  Instead, we must perform +      // lookup and overload resolution. +      CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0); +      if (!CD) +        continue; -  MarkFunctionReferenced(E->getExprLoc(), Destructor); -  CheckDestructorAccess(E->getExprLoc(), Destructor, -                        PDiag(diag::err_access_dtor_exception) << Ty); -  if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) -    return ExprError(); -  return E; +      // Mark the constructor referenced as it is used by this throw expression. +      MarkFunctionReferenced(E->getExprLoc(), CD); + +      // Skip this copy constructor if it is trivial, we don't need to record it +      // in the catchable type data. +      if (CD->isTrivial()) +        continue; + +      // The copy constructor is non-trivial, create a mapping from this class +      // type to this constructor. +      // N.B.  The selection of copy constructor is not sensitive to this +      // particular throw-site.  Lookup will be performed at the catch-site to +      // ensure that the copy constructor is, in fact, accessible (via +      // friendship or any other means). +      Context.addCopyConstructorForExceptionObject(Subobject, CD); + +      // We don't keep the instantiated default argument expressions around so +      // we must rebuild them here. +      for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { +        // Skip any default arguments that we've already instantiated. +        if (Context.getDefaultArgExprForConstructor(CD, I)) +          continue; + +        Expr *DefaultArg = +            BuildCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)).get(); +        Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); +      } +    } +  } + +  return false;  }  QualType Sema::getCurrentThisType() { @@ -982,18 +1064,21 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,    Expr *Inner = Result.get();    if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null<CXXBindTemporaryExpr>(Inner))      Inner = BTE->getSubExpr(); -  if (isa<InitListExpr>(Inner)) { -    // If the list-initialization doesn't involve a constructor call, we'll get -    // the initializer-list (with corrected type) back, but that's not what we -    // want, since it will be treated as an initializer list in further -    // processing. Explicitly insert a cast here. +  if (!isa<CXXTemporaryObjectExpr>(Inner)) { +    // If we created a CXXTemporaryObjectExpr, that node also represents the +    // functional cast. Otherwise, create an explicit cast to represent +    // the syntactic form of a functional-style cast that was used here. +    // +    // FIXME: Creating a CXXFunctionalCastExpr around a CXXConstructExpr +    // would give a more consistent AST representation than using a +    // CXXTemporaryObjectExpr. It's also weird that the functional cast +    // is sometimes handled by initialization and sometimes not.      QualType ResultType = Result.get()->getType();      Result = CXXFunctionalCastExpr::Create(          Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo,          CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc);    } -  // FIXME: Improve AST representation?    return Result;  } @@ -1333,8 +1418,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,                     << ConvTy->isEnumeralType() << ConvTy;          } -        virtual SemaDiagnosticBuilder diagnoseConversion( -            Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { +        SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, +                                                 QualType T, +                                                 QualType ConvTy) override {            return S.Diag(Loc,                          S.getLangOpts().CPlusPlus11                            ? diag::warn_cxx98_compat_array_size_conversion @@ -2048,7 +2134,7 @@ void Sema::DeclareGlobalNewDelete() {  void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,                                             QualType Return,                                             QualType Param1, QualType Param2, -                                           bool AddMallocAttr) { +                                           bool AddRestrictAttr) {    DeclContext *GlobalCtx = Context.getTranslationUnitDecl();    unsigned NumParams = Param2.isNull() ? 1 : 2; @@ -2071,8 +2157,9 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,          // FIXME: Do we need to check for default arguments here?          if (InitialParam1Type == Param1 &&              (NumParams == 1 || InitialParam2Type == Param2)) { -          if (AddMallocAttr && !Func->hasAttr<MallocAttr>()) -            Func->addAttr(MallocAttr::CreateImplicit(Context)); +          if (AddRestrictAttr && !Func->hasAttr<RestrictAttr>()) +            Func->addAttr(RestrictAttr::CreateImplicit( +                Context, RestrictAttr::GNU_malloc));            // Make the function visible to name lookup, even if we found it in            // an unimported module. It either is an implicitly-declared global            // allocation function, or is suppressing that function. @@ -2110,9 +2197,14 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,                           SourceLocation(), Name,                           FnType, /*TInfo=*/nullptr, SC_None, false, true);    Alloc->setImplicit(); +   +  // Implicit sized deallocation functions always have default visibility. +  Alloc->addAttr(VisibilityAttr::CreateImplicit(Context, +                                                VisibilityAttr::Default)); -  if (AddMallocAttr) -    Alloc->addAttr(MallocAttr::CreateImplicit(Context)); +  if (AddRestrictAttr) +    Alloc->addAttr( +        RestrictAttr::CreateImplicit(Context, RestrictAttr::GNU_malloc));    ParmVarDecl *ParamDecls[2];    for (unsigned I = 0; I != NumParams; ++I) { @@ -2247,6 +2339,260 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,    return false;  } +namespace { +/// \brief Checks whether delete-expression, and new-expression used for +///  initializing deletee have the same array form. +class MismatchingNewDeleteDetector { +public: +  enum MismatchResult { +    /// Indicates that there is no mismatch or a mismatch cannot be proven. +    NoMismatch, +    /// Indicates that variable is initialized with mismatching form of \a new. +    VarInitMismatches, +    /// Indicates that member is initialized with mismatching form of \a new. +    MemberInitMismatches, +    /// Indicates that 1 or more constructors' definitions could not been +    /// analyzed, and they will be checked again at the end of translation unit. +    AnalyzeLater +  }; + +  /// \param EndOfTU True, if this is the final analysis at the end of +  /// translation unit. False, if this is the initial analysis at the point +  /// delete-expression was encountered. +  explicit MismatchingNewDeleteDetector(bool EndOfTU) +      : IsArrayForm(false), Field(nullptr), EndOfTU(EndOfTU), +        HasUndefinedConstructors(false) {} + +  /// \brief Checks whether pointee of a delete-expression is initialized with +  /// matching form of new-expression. +  /// +  /// If return value is \c VarInitMismatches or \c MemberInitMismatches at the +  /// point where delete-expression is encountered, then a warning will be +  /// issued immediately. If return value is \c AnalyzeLater at the point where +  /// delete-expression is seen, then member will be analyzed at the end of +  /// translation unit. \c AnalyzeLater is returned iff at least one constructor +  /// couldn't be analyzed. If at least one constructor initializes the member +  /// with matching type of new, the return value is \c NoMismatch. +  MismatchResult analyzeDeleteExpr(const CXXDeleteExpr *DE); +  /// \brief Analyzes a class member. +  /// \param Field Class member to analyze. +  /// \param DeleteWasArrayForm Array form-ness of the delete-expression used +  /// for deleting the \p Field. +  MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm); +  /// List of mismatching new-expressions used for initialization of the pointee +  llvm::SmallVector<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. +  /// E can be a single-element \c InitListExpr consisting of 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 @@ -2362,12 +2708,6 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,        }      } -    // C++ [expr.delete]p2: -    //   [Note: a pointer to a const type can be the operand of a -    //   delete-expression; it is not necessary to cast away the constness -    //   (5.2.11) of the pointer expression before it is used as the operand -    //   of the delete-expression. ] -      if (Pointee->isArrayType() && !ArrayForm) {        Diag(StartLoc, diag::warn_delete_array_type)            << Type << Ex.get()->getSourceRange() @@ -2442,7 +2782,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,            DeleteName);      MarkFunctionReferenced(StartLoc, OperatorDelete); -     +      // Check access and ambiguity of operator delete and destructor.      if (PointeeRD) {        if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { @@ -2452,9 +2792,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,      }    } -  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, @@ -2570,6 +2912,8 @@ static ExprResult BuildCXXCastArgument(Sema &S,      S.CheckConstructorAccess(CastLoc, Constructor,                               InitializedEntity::InitializeTemporary(Ty),                               Constructor->getAccess()); +    if (S.DiagnoseUseOfDecl(Method, CastLoc)) +      return ExprError();      ExprResult Result = S.BuildCXXConstructExpr(          CastLoc, Ty, cast<CXXConstructorDecl>(Method), @@ -2585,6 +2929,10 @@ static ExprResult BuildCXXCastArgument(Sema &S,    case CK_UserDefinedConversion: {      assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); +    S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ nullptr, FoundDecl); +    if (S.DiagnoseUseOfDecl(Method, CastLoc)) +      return ExprError(); +      // Create an implicit call expr that calls it.      CXXConversionDecl *Conv = cast<CXXConversionDecl>(Method);      ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Conv, @@ -2596,8 +2944,6 @@ static ExprResult BuildCXXCastArgument(Sema &S,                                        CK_UserDefinedConversion, Result.get(),                                        nullptr, Result.get()->getValueKind()); -    S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ nullptr, FoundDecl); -      return S.MaybeBindToTemporary(Result.get());    }    } @@ -2628,7 +2974,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,        FunctionDecl *FD = ICS.UserDefined.ConversionFunction;        CastKind CastKind;        QualType BeforeToType; -      assert(FD && "FIXME: aggregate initialization from init list"); +      assert(FD && "no conversion function for user-defined conversion seq");        if (const CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(FD)) {          CastKind = CK_UserDefinedConversion; @@ -2989,8 +3335,18 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,      break;    case ICK_Vector_Splat: -    From = ImpCastExprToType(From, ToType, CK_VectorSplat,  -                             VK_RValue, /*BasePath=*/nullptr, CCK).get(); +    // Vector splat from any arithmetic type to a vector. +    // Cast to the element type. +    { +      QualType elType = ToType->getAs<ExtVectorType>()->getElementType(); +      if (elType != From->getType()) { +        ExprResult E = From; +        From = ImpCastExprToType(From, elType, +                                 PrepareScalarCast(E, elType)).get(); +      } +      From = ImpCastExprToType(From, ToType, CK_VectorSplat, +                               VK_RValue, /*BasePath=*/nullptr, CCK).get(); +    }      break;    case ICK_Complex_Real: @@ -3529,8 +3885,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,        bool FoundConstructor = false;        unsigned FoundTQs; -      DeclContext::lookup_const_result R = Self.LookupConstructors(RD); -      for (DeclContext::lookup_const_iterator Con = R.begin(), +      DeclContext::lookup_result R = Self.LookupConstructors(RD); +      for (DeclContext::lookup_iterator Con = R.begin(),             ConEnd = R.end(); Con != ConEnd; ++Con) {          // A template constructor is never a copy constructor.          // FIXME: However, it may actually be selected at the actual overload @@ -3569,8 +3925,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,          return true;        bool FoundConstructor = false; -      DeclContext::lookup_const_result R = Self.LookupConstructors(RD); -      for (DeclContext::lookup_const_iterator Con = R.begin(), +      DeclContext::lookup_result R = Self.LookupConstructors(RD); +      for (DeclContext::lookup_iterator Con = R.begin(),             ConEnd = R.end(); Con != ConEnd; ++Con) {          // FIXME: In C++0x, a constructor template can be a default constructor.          if (isa<FunctionTemplateDecl>(*Con)) @@ -5139,7 +5495,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {      if (Call == TopCall)        continue; -    if (CheckCallReturnType(Call->getCallReturnType(), +    if (CheckCallReturnType(Call->getCallReturnType(Context),                              Call->getLocStart(),                              Call, Call->getDirectCallee()))        return ExprError(); @@ -5202,10 +5558,11 @@ static void noteOperatorArrows(Sema &S,    }  } -ExprResult -Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, -                                   tok::TokenKind OpKind, ParsedType &ObjectType, -                                   bool &MayBePseudoDestructor) { +ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, +                                              SourceLocation OpLoc, +                                              tok::TokenKind OpKind, +                                              ParsedType &ObjectType, +                                              bool &MayBePseudoDestructor) {    // Since this might be a postfix expression, get rid of ParenListExprs.    ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);    if (Result.isInvalid()) return ExprError(); @@ -5339,20 +5696,6 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc,    return Base;  } -ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, -                                                   Expr *MemExpr) { -  SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc); -  Diag(MemExpr->getLocStart(), diag::err_dtor_expr_without_call) -    << isa<CXXPseudoDestructorExpr>(MemExpr) -    << FixItHint::CreateInsertion(ExpectedLParenLoc, "()"); - -  return ActOnCallExpr(/*Scope*/ nullptr, -                       MemExpr, -                       /*LPLoc*/ ExpectedLParenLoc, -                       None, -                       /*RPLoc*/ ExpectedLParenLoc); -} -  static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,                      tok::TokenKind& OpKind, SourceLocation OpLoc) {    if (Base->hasPlaceholderType()) { @@ -5393,8 +5736,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,                                             TypeSourceInfo *ScopeTypeInfo,                                             SourceLocation CCLoc,                                             SourceLocation TildeLoc, -                                         PseudoDestructorTypeStorage Destructed, -                                           bool HasTrailingLParen) { +                                         PseudoDestructorTypeStorage Destructed) {    TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();    QualType ObjectType; @@ -5482,10 +5824,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,                                              TildeLoc,                                              Destructed); -  if (HasTrailingLParen) -    return Result; - -  return DiagnoseDtorReference(Destructed.getLocation(), Result); +  return Result;  }  ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, @@ -5495,8 +5834,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,                                             UnqualifiedId &FirstTypeName,                                             SourceLocation CCLoc,                                             SourceLocation TildeLoc, -                                           UnqualifiedId &SecondTypeName, -                                           bool HasTrailingLParen) { +                                           UnqualifiedId &SecondTypeName) {    assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||            FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&           "Invalid first type name in pseudo-destructor"); @@ -5623,15 +5961,14 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,    return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS,                                     ScopeTypeInfo, CCLoc, TildeLoc, -                                   Destructed, HasTrailingLParen); +                                   Destructed);  }  ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,                                             SourceLocation OpLoc,                                             tok::TokenKind OpKind,                                             SourceLocation TildeLoc,  -                                           const DeclSpec& DS, -                                           bool HasTrailingLParen) { +                                           const DeclSpec& DS) {    QualType ObjectType;    if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))      return ExprError(); @@ -5647,7 +5984,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,    return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(),                                     nullptr, SourceLocation(), TildeLoc, -                                   Destructed, HasTrailingLParen); +                                   Destructed);  }  ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, @@ -5685,10 +6022,9 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,    if (Exp.isInvalid())      return true; -  MemberExpr *ME = -      new (Context) MemberExpr(Exp.get(), /*IsArrow=*/false, Method, -                               SourceLocation(), Context.BoundMemberTy, -                               VK_RValue, OK_Ordinary); +  MemberExpr *ME = new (Context) MemberExpr( +      Exp.get(), /*IsArrow=*/false, SourceLocation(), Method, SourceLocation(), +      Context.BoundMemberTy, VK_RValue, OK_Ordinary);    if (HadMultipleCandidates)      ME->setHadMultipleCandidates(true);    MarkMemberReferenced(ME); @@ -6052,6 +6388,8 @@ public:  class TransformTypos : public TreeTransform<TransformTypos> {    typedef TreeTransform<TransformTypos> BaseTransform; +  VarDecl *InitDecl; // A decl to avoid as a correction because it is in the +                     // process of being initialized.    llvm::function_ref<ExprResult(Expr *)> ExprFilter;    llvm::SmallSetVector<TypoExpr *, 2> TypoExprs, AmbiguousTypoExprs;    llvm::SmallDenseMap<TypoExpr *, ExprResult, 2> TransformCache; @@ -6130,8 +6468,8 @@ class TransformTypos : public TreeTransform<TransformTypos> {    }  public: -  TransformTypos(Sema &SemaRef, llvm::function_ref<ExprResult(Expr *)> Filter) -      : BaseTransform(SemaRef), ExprFilter(Filter) {} +  TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref<ExprResult(Expr *)> Filter) +      : BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {}    ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc,                                     MultiExprArg Args, @@ -6210,6 +6548,8 @@ public:      // For the first TypoExpr and an uncached TypoExpr, find the next likely      // typo correction and return it.      while (TypoCorrection TC = State.Consumer->getNextCorrection()) { +      if (InitDecl && TC.getCorrectionDecl() == InitDecl) +        continue;        ExprResult NE = State.RecoveryHandler ?            State.RecoveryHandler(SemaRef, E, TC) :            attemptRecovery(SemaRef, *State.Consumer, TC); @@ -6234,8 +6574,9 @@ public:  };  } -ExprResult Sema::CorrectDelayedTyposInExpr( -    Expr *E, llvm::function_ref<ExprResult(Expr *)> Filter) { +ExprResult +Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, +                                llvm::function_ref<ExprResult(Expr *)> Filter) {    // If the current evaluation context indicates there are uncorrected typos    // and the current expression isn't guaranteed to not have typos, try to    // resolve any TypoExpr nodes that might be in the expression. @@ -6246,7 +6587,7 @@ ExprResult Sema::CorrectDelayedTyposInExpr(      assert(TyposInContext < ~0U && "Recursive call of CorrectDelayedTyposInExpr");      ExprEvalContexts.back().NumTypos = ~0U;      auto TyposResolved = DelayedTypos.size(); -    auto Result = TransformTypos(*this, Filter).Transform(E); +    auto Result = TransformTypos(*this, InitDecl, Filter).Transform(E);      ExprEvalContexts.back().NumTypos = TyposInContext;      TyposResolved -= DelayedTypos.size();      if (Result.isInvalid() || Result.get() != E) { | 
