diff options
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 24 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 1 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 48 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 26 | ||||
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 5 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 9 |
6 files changed, 94 insertions, 19 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index dc99d4dabd4..6b840b9e475 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1572,6 +1572,30 @@ bool ASTContext::isAlignmentRequired(QualType T) const { return isAlignmentRequired(T.getTypePtr()); } +unsigned ASTContext::getTypeAlignIfKnown(QualType T) const { + // An alignment on a typedef overrides anything else. + if (auto *TT = T->getAs<TypedefType>()) + if (unsigned Align = TT->getDecl()->getMaxAlignment()) + return Align; + + // If we have an (array of) complete type, we're done. + T = getBaseElementType(T); + if (!T->isIncompleteType()) + return getTypeAlign(T); + + // If we had an array type, its element type might be a typedef + // type with an alignment attribute. + if (auto *TT = T->getAs<TypedefType>()) + if (unsigned Align = TT->getDecl()->getMaxAlignment()) + return Align; + + // Otherwise, see if the declaration of the type had an attribute. + if (auto *TT = T->getAs<TagType>()) + return TT->getDecl()->getMaxAlignment(); + + return 0; +} + TypeInfo ASTContext::getTypeInfo(const Type *T) const { TypeInfoMap::iterator I = MemoizedTypeInfo.find(T); if (I != MemoizedTypeInfo.end()) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index d03de30d1b4..9e17c0c3de5 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6330,6 +6330,7 @@ Expr *ASTNodeImporter::VisitCXXNewExpr(CXXNewExpr *CE) { Importer.getToContext(), CE->isGlobalNew(), OperatorNewDecl, OperatorDeleteDecl, + CE->passAlignment(), CE->doesUsualArrayDeleteWantSize(), PlacementArgs, Importer.Import(CE->getTypeIdParens()), diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index fec7df0ffb7..e330e31d47f 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2596,7 +2596,7 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { return false; const auto *FPT = getType()->castAs<FunctionProtoType>(); - if (FPT->getNumParams() == 0 || FPT->getNumParams() > 2 || FPT->isVariadic()) + if (FPT->getNumParams() == 0 || FPT->getNumParams() > 3 || FPT->isVariadic()) return false; // If this is a single-parameter function, it must be a replaceable global @@ -2604,20 +2604,42 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { if (FPT->getNumParams() == 1) return true; - // Otherwise, we're looking for a second parameter whose type is - // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'. - QualType Ty = FPT->getParamType(1); + unsigned Params = 1; + QualType Ty = FPT->getParamType(Params); ASTContext &Ctx = getASTContext(); + + auto Consume = [&] { + ++Params; + Ty = Params < FPT->getNumParams() ? FPT->getParamType(Params) : QualType(); + }; + + // In C++14, the next parameter can be a 'std::size_t' for sized delete. + bool IsSizedDelete = false; if (Ctx.getLangOpts().SizedDeallocation && - Ctx.hasSameType(Ty, Ctx.getSizeType())) - return true; - if (!Ty->isReferenceType()) - return false; - Ty = Ty->getPointeeType(); - if (Ty.getCVRQualifiers() != Qualifiers::Const) - return false; - const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); - return RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace(); + (getDeclName().getCXXOverloadedOperator() == OO_Delete || + getDeclName().getCXXOverloadedOperator() == OO_Array_Delete) && + Ctx.hasSameType(Ty, Ctx.getSizeType())) { + IsSizedDelete = true; + Consume(); + } + + // In C++17, the next parameter can be a 'std::align_val_t' for aligned + // new/delete. + if (Ctx.getLangOpts().AlignedAllocation && !Ty.isNull() && Ty->isAlignValT()) + Consume(); + + // Finally, if this is not a sized delete, the final parameter can + // be a 'const std::nothrow_t&'. + if (!IsSizedDelete && !Ty.isNull() && Ty->isReferenceType()) { + Ty = Ty->getPointeeType(); + if (Ty.getCVRQualifiers() != Qualifiers::Const) + return false; + const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + if (RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace()) + Consume(); + } + + return Params == FPT->getNumParams(); } LanguageLinkage FunctionDecl::getLanguageLinkage() const { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index d7472fcc358..97f75a02052 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1577,17 +1577,35 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { // deallocation function. [...] if (getNumParams() == 1) return true; + unsigned UsualParams = 1; - // C++ [basic.stc.dynamic.deallocation]p2: + // C++ <=14 [basic.stc.dynamic.deallocation]p2: // [...] If class T does not declare such an operator delete but does // declare a member deallocation function named operator delete with // exactly two parameters, the second of which has type std::size_t (18.1), // then this function is a usual deallocation function. + // + // C++17 says a usual deallocation function is one with the signature + // (void* [, size_t] [, std::align_val_t] [, ...]) + // and all such functions are usual deallocation functions. It's not clear + // that allowing varargs functions was intentional. ASTContext &Context = getASTContext(); - if (getNumParams() != 2 || - !Context.hasSameUnqualifiedType(getParamDecl(1)->getType(), - Context.getSizeType())) + if (UsualParams < getNumParams() && + Context.hasSameUnqualifiedType(getParamDecl(UsualParams)->getType(), + Context.getSizeType())) + ++UsualParams; + + if (UsualParams < getNumParams() && + getParamDecl(UsualParams)->getType()->isAlignValT()) + ++UsualParams; + + if (UsualParams != getNumParams()) return false; + + // In C++17 onwards, all potential usual deallocation functions are actual + // usual deallocation functions. + if (Context.getLangOpts().AlignedAllocation) + return true; // This function is a usual deallocation function if there are no // single-parameter deallocation functions of the same kind. diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index a13033d4746..3efb5b1cbc1 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -62,7 +62,7 @@ SourceLocation CXXScalarValueInitExpr::getLocStart() const { // CXXNewExpr CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew, FunctionDecl *operatorNew, FunctionDecl *operatorDelete, - bool usualArrayDeleteWantsSize, + bool PassAlignment, bool usualArrayDeleteWantsSize, ArrayRef<Expr*> placementArgs, SourceRange typeIdParens, Expr *arraySize, InitializationStyle initializationStyle, @@ -76,7 +76,8 @@ CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew, SubExprs(nullptr), OperatorNew(operatorNew), OperatorDelete(operatorDelete), AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens), Range(Range), DirectInitRange(directInitRange), - GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { + GlobalNew(globalNew), PassAlignment(PassAlignment), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { assert((initializer != nullptr || initializationStyle == NoInit) && "Only NoInit can have no initializer."); StoredInitializationStyle = initializer ? initializationStyle + 1 : 0; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 4aa07568dc7..113974c4b60 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2337,6 +2337,15 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { return false; } +bool Type::isAlignValT() const { + if (auto *ET = getAs<EnumType>()) { + auto *II = ET->getDecl()->getIdentifier(); + if (II && II->isStr("align_val_t") && ET->getDecl()->isInStdNamespace()) + return true; + } + return false; +} + bool Type::isPromotableIntegerType() const { if (const BuiltinType *BT = getAs<BuiltinType>()) switch (BT->getKind()) { |