blob: 5af6398c2ca1f2df8a48e0cb884a4c64cf4259af [file] [log] [blame]
--- tools/clang/tools/include-what-you-use/iwyu_ast_util.cc.orig 2020-03-23 14:03:01.060932783 -0700
+++ tools/clang/tools/include-what-you-use/iwyu_ast_util.cc 2020-03-23 14:04:37.056235116 -0700
@@ -47,6 +47,7 @@
class FileEntry;
} // namespace clang
+using clang::ASTContext;
using clang::BlockPointerType;
using clang::CXXConstructExpr;
using clang::CXXConstructorDecl;
@@ -78,6 +79,7 @@
using clang::FullSourceLoc;
using clang::FunctionDecl;
using clang::FunctionType;
+using clang::IdentifierInfo;
using clang::ImplicitCastExpr;
using clang::InjectedClassNameType;
using clang::LValueReferenceType;
@@ -929,13 +931,81 @@
!StartsWith(decl_name, "operator delete"))
return false;
- // Placement-new/delete has 2 args, second is void*. The only other
- // 2-arg overloads of new/delete in <new> take a const nothrow_t&.
- if (decl->getNumParams() == 2 &&
- !decl->getParamDecl(1)->getType().isConstQualified())
- return false;
-
- return true;
+ // The following variants of operator new[1] are implicitly defined in every
+ // translation unit and should not require including <new>.
+ //
+ // void* operator new ( std::size_t count );
+ // void* operator new[]( std::size_t count );
+ // void* operator new ( std::size_t count, std::align_val_t al ); (since C++17)
+ // void* operator new[]( std::size_t count, std::align_val_t al ); (since C++17)
+ //
+ // Likewise, the following variants of operator delete[2] are implicitly
+ // defined in every translation unit and should not require including <new>.
+ //
+ // void operator delete ( void* ptr ) throw(); (until C++11)
+ // void operator delete ( void* ptr ) noexcept; (since C++11)
+ // void operator delete[]( void* ptr ) throw(); (until C++11)
+ // void operator delete[]( void* ptr ) noexcept; (since C++11)
+ // void operator delete ( void* ptr, std::align_val_t al ) noexcept; (since C++17)
+ // void operator delete[]( void* ptr, std::align_val_t al ) noexcept; (since C++17)
+ // void operator delete ( void* ptr, std::size_t sz ) noexcept; (since C++14)
+ // void operator delete[]( void* ptr, std::size_t sz ) noexcept; (since C++14)
+ // void operator delete ( void* ptr, std::size_t sz,
+ // std::align_val_t al ) noexcept; (since C++17)
+ // void operator delete[]( void* ptr, std::size_t sz,
+ // std::align_val_t al ) noexcept; (since C++17)
+ // void operator delete ( void* ptr, const std::nothrow_t& tag ) throw(); (until C++11)
+ // void operator delete ( void* ptr, const std::nothrow_t& tag ) noexcept; (since C++11)
+ // void operator delete[]( void* ptr, const std::nothrow_t& tag ) throw(); (until C++11)
+ // void operator delete[]( void* ptr, const std::nothrow_t& tag ) noexcept; (since C++11)
+ //
+ // The below code attempts to return true for these variants while returning
+ // false for all others. FunctionDecl::isReplaceableGlobalAllocationFunction
+ // comes very very close, but returns true for nothrow new, which is not
+ // implicitly defined.
+ //
+ // 1. https://en.cppreference.com/w/cpp/memory/new/operator_new
+ // 2. https://en.cppreference.com/w/cpp/memory/new/operator_delete
+ switch (decl->getNumParams()) {
+ case 1:
+ // All 1-arg variants are implicitly declared.
+ return true;
+ case 2: {
+ // Amongst 2-arg variants, aligned (C++17) new/delete, sized delete (C++14), and
+ // nothrow delete are implicitly declared.
+ ASTContext& ctx = decl->getASTContext();
+ QualType t = decl->getParamDecl(1)->getType();
+ if (t->isAlignValT() || // aligned new/delete
+ ctx.hasSameType(t, ctx.getSizeType())) // sized delete
+ return true;
+ // We have to work a bit harder to figure out if it's a nothrow delete.
+ //
+ // This cribs from FunctionDecl::isReplaceableGlobalAllocationFunction.
+ if (StartsWith(decl_name, "operator delete") && t->isReferenceType()) {
+ t = t->getPointeeType();
+ if (t.isConstQualified()) {
+ const CXXRecordDecl* recordDecl = t->getAsCXXRecordDecl();
+ if (recordDecl) {
+ const IdentifierInfo* iInfo = recordDecl->getIdentifier();
+ if (iInfo && iInfo->isStr("nothrow_t") && recordDecl->isInStdNamespace())
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ case 3: {
+ // Amongst 3-arg variants, only sized aligned delete (C++17) is implicitly
+ // declared.
+ ASTContext& ctx = decl->getASTContext();
+ QualType t = decl->getParamDecl(1)->getType();
+ return ctx.hasSameType(t, ctx.getSizeType()) &&
+ decl->getParamDecl(2)->getType()->isAlignValT();
+ }
+ default:
+ return false;
+ return true;
+ }
}
bool IsFriendDecl(const Decl* decl) {
@@ -1082,7 +1152,7 @@
bool IsBuiltinFunction(const clang::NamedDecl* decl,
const std::string& symbol_name) {
- if (const clang::IdentifierInfo* iden = decl->getIdentifier()) {
+ if (const IdentifierInfo* iden = decl->getIdentifier()) {
return iden->getBuiltinID() != 0 &&
!clang::Builtin::Context::isBuiltinFunc(symbol_name.c_str());
}