diff options
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 124 |
1 files changed, 94 insertions, 30 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index a9cf3ec7990b2..9c842ded1e101 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -24,6 +24,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -1377,9 +1378,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, /// \brief Determine whether the given function is a non-placement /// deallocation function. static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { - if (FD->isInvalidDecl()) - return false; - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) return Method->isUsualDeallocationFunction(); @@ -1409,14 +1407,20 @@ namespace { UsualDeallocFnInfo() : Found(), FD(nullptr) {} UsualDeallocFnInfo(Sema &S, DeclAccessPair Found) : Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())), - HasSizeT(false), HasAlignValT(false), CUDAPref(Sema::CFP_Native) { + Destroying(false), HasSizeT(false), HasAlignValT(false), + CUDAPref(Sema::CFP_Native) { // A function template declaration is never a usual deallocation function. if (!FD) return; - if (FD->getNumParams() == 3) + unsigned NumBaseParams = 1; + if (FD->isDestroyingOperatorDelete()) { + Destroying = true; + ++NumBaseParams; + } + if (FD->getNumParams() == NumBaseParams + 2) HasAlignValT = HasSizeT = true; - else if (FD->getNumParams() == 2) { - HasSizeT = FD->getParamDecl(1)->getType()->isIntegerType(); + else if (FD->getNumParams() == NumBaseParams + 1) { + HasSizeT = FD->getParamDecl(NumBaseParams)->getType()->isIntegerType(); HasAlignValT = !HasSizeT; } @@ -1430,6 +1434,12 @@ namespace { bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize, bool WantAlign) const { + // C++ P0722: + // A destroying operator delete is preferred over a non-destroying + // operator delete. + if (Destroying != Other.Destroying) + return Destroying; + // C++17 [expr.delete]p10: // If the type has new-extended alignment, a function with a parameter // of type std::align_val_t is preferred; otherwise a function without @@ -1446,7 +1456,7 @@ namespace { DeclAccessPair Found; FunctionDecl *FD; - bool HasSizeT, HasAlignValT; + bool Destroying, HasSizeT, HasAlignValT; Sema::CUDAFunctionPreference CUDAPref; }; } @@ -1660,9 +1670,13 @@ static void diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, bool IsAligned = false; if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) { + const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple(); + StringRef OSName = AvailabilityAttr::getPlatformNameSourceSpelling( + S.getASTContext().getTargetInfo().getPlatformName()); + S.Diag(Loc, diag::warn_aligned_allocation_unavailable) - << IsDelete << FD.getType().getAsString() - << S.getASTContext().getTargetInfo().getTriple().str(); + << IsDelete << FD.getType().getAsString() << OSName + << alignedAllocMinVersion(T.getOS()).getAsString(); S.Diag(Loc, diag::note_silence_unligned_allocation_unavailable); } } @@ -1734,20 +1748,27 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (AllocType.isNull()) return ExprError(); } else if (Deduced) { + bool Braced = (initStyle == CXXNewExpr::ListInit); + if (NumInits == 1) { + if (auto p = dyn_cast_or_null<InitListExpr>(Inits[0])) { + Inits = p->getInits(); + NumInits = p->getNumInits(); + Braced = true; + } + } + if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); - if (initStyle == CXXNewExpr::ListInit || - (NumInits == 1 && isa<InitListExpr>(Inits[0]))) - return ExprError(Diag(Inits[0]->getLocStart(), - diag::err_auto_new_list_init) - << AllocType << TypeRange); if (NumInits > 1) { Expr *FirstBad = Inits[1]; return ExprError(Diag(FirstBad->getLocStart(), diag::err_auto_new_ctor_multiple_expressions) << AllocType << TypeRange); } + if (Braced && !getLangOpts().CPlusPlus17) + Diag(Initializer->getLocStart(), diag::ext_auto_new_list_init) + << AllocType << TypeRange; Expr *Deduce = Inits[0]; QualType DeducedType; if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) @@ -2099,7 +2120,7 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; - else if (AllocType.getAddressSpace()) + else if (AllocType.getAddressSpace() != LangAS::Default) return Diag(Loc, diag::err_address_space_qualified_new) << AllocType.getUnqualifiedType() << AllocType.getQualifiers().getAddressSpaceAttributePrintValue(); @@ -3171,7 +3192,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); - if (Pointee.getAddressSpace()) + if (Pointee.getAddressSpace() != LangAS::Default) return Diag(Ex.get()->getLocStart(), diag::err_address_space_qualified_delete) << Pointee.getUnqualifiedType() @@ -3259,16 +3280,39 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, MarkFunctionReferenced(StartLoc, OperatorDelete); - // Check access and ambiguity of operator delete and destructor. + // Check access and ambiguity of destructor if we're going to call it. + // Note that this is required even for a virtual delete. + bool IsVirtualDelete = false; if (PointeeRD) { if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { - CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, - PDiag(diag::err_access_dtor) << PointeeElem); + CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, + PDiag(diag::err_access_dtor) << PointeeElem); + IsVirtualDelete = Dtor->isVirtual(); } } diagnoseUnavailableAlignedAllocation(*OperatorDelete, StartLoc, true, *this); + + // Convert the operand to the type of the first parameter of operator + // delete. This is only necessary if we selected a destroying operator + // delete that we are going to call (non-virtually); converting to void* + // is trivial and left to AST consumers to handle. + QualType ParamType = OperatorDelete->getParamDecl(0)->getType(); + if (!IsVirtualDelete && !ParamType->getPointeeType()->isVoidType()) { + Qualifiers Qs = Pointee.getQualifiers(); + if (Qs.hasCVRQualifiers()) { + // Qualifiers are irrelevant to this conversion; we're only looking + // for access and ambiguity. + Qs.removeCVRQualifiers(); + QualType Unqual = Context.getPointerType( + Context.getQualifiedType(Pointee.getUnqualifiedType(), Qs)); + Ex = ImpCastExprToType(Ex.get(), Unqual, CK_NoOp); + } + Ex = PerformImplicitConversion(Ex.get(), ParamType, AA_Passing); + if (Ex.isInvalid()) + return ExprError(); + } } CXXDeleteExpr *Result = new (Context) CXXDeleteExpr( @@ -3282,7 +3326,7 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc) { - if (!dtor || dtor->isVirtual() || !CallCanBeVirtual) + if (!dtor || dtor->isVirtual() || !CallCanBeVirtual || isUnevaluatedContext()) return; // C++ [expr.delete]p3: @@ -3297,6 +3341,12 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr<FinalAttr>()) return; + // If the superclass is in a system header, there's nothing that can be done. + // The `delete` (where we emit the warning) can be in a system header, + // what matters for this warning is where the deleted type is defined. + if (getSourceManager().isInSystemHeader(PointeeRD->getLocation())) + return; + QualType ClassType = dtor->getThisType(Context)->getPointeeType(); if (PointeeRD->isAbstract()) { // If the class is abstract, we warn by default, because we're @@ -3797,7 +3847,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, << From->getSourceRange(); } - CastKind Kind = CK_Invalid; + CastKind Kind; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); @@ -3817,7 +3867,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } case ICK_Pointer_Member: { - CastKind Kind = CK_Invalid; + CastKind Kind; CXXCastPath BasePath; if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); @@ -4141,6 +4191,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_IsDestructible: case UTT_IsNothrowDestructible: case UTT_IsTriviallyDestructible: + case UTT_HasUniqueObjectRepresentations: if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) return true; @@ -4580,6 +4631,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, // Returns True if and only if T is a complete type at the point of the // function call. return !T->isIncompleteType(); + case UTT_HasUniqueObjectRepresentations: + return C.hasUniqueObjectRepresentations(T); } } @@ -4790,9 +4843,13 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, } case BTT_IsSame: return Self.Context.hasSameType(LhsT, RhsT); - case BTT_TypeCompatible: - return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), - RhsT.getUnqualifiedType()); + case BTT_TypeCompatible: { + // GCC ignores cv-qualifiers on arrays for this builtin. + Qualifiers LhsQuals, RhsQuals; + QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals); + QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals); + return Self.Context.typesAreCompatible(Lhs, Rhs); + } case BTT_IsConvertible: case BTT_IsConvertibleTo: { // C++0x [meta.rel]p4: @@ -5173,9 +5230,16 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, break; case RQ_LValue: - if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) - Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RHSType << 1 << LHS.get()->getSourceRange(); + if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) { + // C++2a allows functions with ref-qualifier & if they are also 'const'. + if (Proto->isConst()) + Diag(Loc, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue + : diag::ext_pointer_to_const_ref_member_on_rvalue); + else + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RHSType << 1 << LHS.get()->getSourceRange(); + } break; case RQ_RValue: @@ -5702,7 +5766,7 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, // happen in C++17, because it would mean we were computing the composite // pointer type of dependent types, which should never happen. if (EST1 == EST_ComputedNoexcept || EST2 == EST_ComputedNoexcept) { - assert(!S.getLangOpts().CPlusPlus1z && + assert(!S.getLangOpts().CPlusPlus17 && "computing composite pointer type of dependent types"); return FunctionProtoType::ExceptionSpecInfo(); } |