diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp | 623 |
1 files changed, 482 insertions, 141 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index a92b7ac..7e305ff 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/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) { |