================ @@ -0,0 +1,488 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "UseConstexprCheck.h" +#include "../utils/ASTUtils.h" +#include "../utils/LexerUtils.h" +#include "clang/AST/Decl.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { +AST_MATCHER(FunctionDecl, locationPermitsConstexpr) { + const bool IsInMainFile = + Finder->getASTContext().getSourceManager().isInMainFile( + Node.getLocation()); + + if (IsInMainFile) + return !Node.hasExternalFormalLinkage(); + return Node.isInlined(); +} + +AST_MATCHER(Expr, isCXX11ConstantExpr) { + return !Node.isValueDependent() && + Node.isCXX11ConstantExpr(Finder->getASTContext()); +} + +AST_MATCHER(DeclaratorDecl, isInMacro) { + const SourceRange R = + SourceRange(Node.getTypeSpecStartLoc(), Node.getLocation()); + + return Node.getLocation().isMacroID() || Node.getEndLoc().isMacroID() || + utils::rangeContainsMacroExpansion( + R, &Finder->getASTContext().getSourceManager()) || + utils::rangeIsEntirelyWithinMacroArgument( + R, &Finder->getASTContext().getSourceManager()); +} + +AST_MATCHER(Decl, hasNoRedecl) { + // There is always the actual declaration + return !Node.redecls().empty() && + std::next(Node.redecls_begin()) == Node.redecls_end(); +} + +AST_MATCHER(Decl, allRedeclsInSameFile) { + const SourceManager &SM = Finder->getASTContext().getSourceManager(); + const SourceLocation L = Node.getLocation(); + return llvm::all_of(Node.redecls(), [&](const Decl *ReDecl) { + return SM.isWrittenInSameFile(L, ReDecl->getLocation()); + }); +} +} // namespace + +static bool +satisfiesConstructorPropertiesUntil20(const CXXConstructorDecl *Ctor, + ASTContext &Ctx) { + const CXXRecordDecl *Rec = Ctor->getParent(); + + llvm::SmallPtrSet<const FieldDecl *, 8> UninitializedFields{ + Rec->field_begin(), Rec->field_end()}; + llvm::SmallPtrSet<const FieldDecl *, 4> Indirects{}; + + for (const CXXCtorInitializer *const Init : Ctor->inits()) { + if (const Type *InitType = Init->getBaseClass(); + InitType && InitType->isRecordType()) { + const auto *ConstructingInit = + llvm::dyn_cast<CXXConstructExpr>(Init->getInit()); + if (ConstructingInit && + !ConstructingInit->getConstructor()->isConstexprSpecified()) + return false; + } + + if (Init->isBaseInitializer()) + continue; + + if (Init->isMemberInitializer()) { + const FieldDecl *Field = Init->getMember(); + + if (Field->isAnonymousStructOrUnion()) + Indirects.insert(Field); + + UninitializedFields.erase(Field); + } + } + + for (const auto &Match : + match(cxxRecordDecl(forEach(indirectFieldDecl().bind("indirect"))), *Rec, + Ctx)) { + const auto *IField = Match.getNodeAs<IndirectFieldDecl>("indirect"); + + size_t NumInitializations = false; + for (const NamedDecl *ND : IField->chain()) + NumInitializations += Indirects.erase(llvm::dyn_cast<FieldDecl>(ND)); + + if (NumInitializations != 1) + return false; + + for (const NamedDecl *ND : IField->chain()) + UninitializedFields.erase(llvm::dyn_cast<FieldDecl>(ND)); + } + + return UninitializedFields.empty(); +} + +static bool isLiteralType(QualType QT, const ASTContext &Ctx, + bool ConservativeLiteralType); + +static bool isLiteralType(const Type *T, const ASTContext &Ctx, + const bool ConservativeLiteralType) { + if (!T) + return false; + + if (!T->isLiteralType(Ctx)) + return false; + + if (!ConservativeLiteralType) + return T->isLiteralType(Ctx) && !T->isVoidType(); + + if (T->isIncompleteType() || T->isIncompleteArrayType()) + return false; + + T = utils::unwrapPointee(T); + if (!T) + return false; + + assert(!T->isPointerOrReferenceType()); + + if (T->isIncompleteType() || T->isIncompleteArrayType()) + return false; + + if (T->isLiteralType(Ctx)) + return true; + + if (const CXXRecordDecl *Rec = T->getAsCXXRecordDecl()) { + if (!Rec->hasDefinition()) + return false; + + if (!Rec->hasTrivialDestructor()) + return false; + + if (!llvm::all_of(Rec->fields(), [&](const FieldDecl *Field) { + return isLiteralType(Field->getType(), Ctx, ConservativeLiteralType); + })) + return false; + + if (llvm::any_of(Rec->ctors(), [](const CXXConstructorDecl *Ctor) { + return !Ctor->isCopyOrMoveConstructor() && + Ctor->isConstexprSpecified(); + })) + return false; + + const auto AllBaseClassesAreLiteralTypes = + llvm::all_of(Rec->bases(), [&](const CXXBaseSpecifier &Base) { + return isLiteralType(Base.getType(), Ctx, ConservativeLiteralType); + }); + if (!AllBaseClassesAreLiteralTypes) + return false; + } ---------------- localspook wrote:
Should there be a `return true;` at the end of this if block? Because otherwise, it seems we *never* return true for a `CXXConstructorDecl` (if we got past all the `return false;` codepaths in this block, we continue to the `getArrayElementTypeNoTypeQual` test below, which fails, because a `CXXConstructorDecl` can't be an array, and end up at... `return false`). https://github.com/llvm/llvm-project/pull/162741 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
