[clang-tools-extra] [clang-tidy] add modernize-use-constexpr check (PR #146553)
Julian Schmidt via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 1 15:53:54 PDT 2025
https://github.com/5chmidti updated https://github.com/llvm/llvm-project/pull/146553
>From 16d5a3fb942673d1fda0ef4b17363a0b5d634fbb Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Fri, 6 Sep 2024 22:58:46 +0200
Subject: [PATCH 01/11] [clang-tidy] add misc-constexpr check
This check finds all functions and variables that can be declared as
`constexpr`, using the specified standard version to check if the
requirements are met.
Fixes #115622
---
.../clang-tidy/misc/CMakeLists.txt | 1 +
.../clang-tidy/misc/MiscTidyModule.cpp | 2 +
.../clang-tidy/misc/UseConstexprCheck.cpp | 946 ++++++++++++++++++
.../clang-tidy/misc/UseConstexprCheck.h | 43 +
.../docs/clang-tidy/checks/list.rst | 1 +
.../clang-tidy/checks/misc/use-constexpr.rst | 40 +
.../checkers/misc/use-constexpr-cxx20.cpp | 36 +
.../checkers/misc/use-constexpr.cpp | 562 +++++++++++
8 files changed, 1631 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/misc/UseConstexprCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/misc/UseConstexprCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/misc/use-constexpr.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr-cxx20.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
index fd7affd22a463..b1630f72f4409 100644
--- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -19,6 +19,7 @@ set_target_properties(genconfusable PROPERTIES FOLDER "Clang Tools Extra/Sourceg
add_clang_library(clangTidyMiscModule STATIC
ConstCorrectnessCheck.cpp
+ UseConstexprCheck.cpp
CoroutineHostileRAIICheck.cpp
DefinitionsInHeadersCheck.cpp
ConfusableIdentifierCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
index 6ddebcbc0e152..38e829cc2004f 100644
--- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -31,6 +31,7 @@
#include "UnusedParametersCheck.h"
#include "UnusedUsingDeclsCheck.h"
#include "UseAnonymousNamespaceCheck.h"
+#include "UseConstexprCheck.h"
#include "UseInternalLinkageCheck.h"
namespace clang::tidy {
@@ -43,6 +44,7 @@ class MiscModule : public ClangTidyModule {
"misc-confusable-identifiers");
CheckFactories.registerCheck<ConstCorrectnessCheck>(
"misc-const-correctness");
+ CheckFactories.registerCheck<UseConstexprCheck>("misc-use-constexpr");
CheckFactories.registerCheck<CoroutineHostileRAIICheck>(
"misc-coroutine-hostile-raii");
CheckFactories.registerCheck<DefinitionsInHeadersCheck>(
diff --git a/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.cpp b/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.cpp
new file mode 100644
index 0000000000000..e6874dcabedbb
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.cpp
@@ -0,0 +1,946 @@
+//===--- UseConstexprCheck.cpp - clang-tidy--------------------------------===//
+//
+// 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/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TokenKinds.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Casting.h"
+#include <cstddef>
+#include <functional>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::misc {
+
+namespace {
+AST_MATCHER(FunctionDecl, locationPermitsConstexpr) {
+ const bool IsInMainFile =
+ Finder->getASTContext().getSourceManager().isInMainFile(
+ Node.getLocation());
+
+ if (IsInMainFile && Node.hasExternalFormalLinkage())
+ return false;
+ if (!IsInMainFile && !Node.isInlined())
+ return false;
+
+ return true;
+}
+
+AST_MATCHER(Expr, isCXX11ConstantExpr) {
+ return !Node.isValueDependent() &&
+ Node.isCXX11ConstantExpr(Finder->getASTContext());
+}
+
+AST_MATCHER(DeclaratorDecl, isInMacro) {
+ const SourceRange R =
+ SourceRange(Node.getInnerLocStart(), 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();
+ for (const Decl *ReDecl : Node.redecls()) {
+ if (!SM.isWrittenInSameFile(L, ReDecl->getLocation()))
+ return false;
+ }
+ return true;
+}
+
+AST_MATCHER(FunctionDecl, isConstexprSpecified) {
+ return Node.isConstexprSpecified();
+}
+
+bool satisfiesConstructorPropertiesUntil20(const CXXConstructorDecl *Ctor,
+ ASTContext &Ctx) {
+ const CXXRecordDecl *Rec = Ctor->getParent();
+ llvm::SmallPtrSet<const RecordDecl *, 8> Bases{};
+ for (const CXXBaseSpecifier Base : Rec->bases()) {
+ Bases.insert(Base.getType()->getAsRecordDecl());
+ }
+ llvm::SmallPtrSet<const FieldDecl *, 8> Fields{Rec->field_begin(),
+ Rec->field_end()};
+ llvm::SmallPtrSet<const FieldDecl *, 4> Indirects{};
+
+ for (const CXXCtorInitializer *const Init : Ctor->inits()) {
+ const Type *InitType = Init->getBaseClass();
+ if (InitType && InitType->isRecordType()) {
+ const auto *ConstructingInit =
+ llvm::dyn_cast<CXXConstructExpr>(Init->getInit());
+ if (ConstructingInit &&
+ !ConstructingInit->getConstructor()->isConstexprSpecified())
+ return false;
+ }
+
+ if (Init->isBaseInitializer()) {
+ Bases.erase(Init->getBaseClass()->getAsRecordDecl());
+ continue;
+ }
+
+ if (Init->isMemberInitializer()) {
+ const FieldDecl *Field = Init->getMember();
+
+ if (Field->isAnonymousStructOrUnion())
+ Indirects.insert(Field);
+
+ Fields.erase(Field);
+ continue;
+ }
+ }
+
+ 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())
+ Fields.erase(llvm::dyn_cast<FieldDecl>(ND));
+ }
+
+ if (!Fields.empty())
+ return false;
+
+ return true;
+}
+
+const Type *unwrapPointee(const Type *T) {
+ if (!T->isPointerOrReferenceType())
+ return T;
+
+ while (T && T->isPointerOrReferenceType()) {
+ if (T->isReferenceType()) {
+ const QualType QType = T->getPointeeType();
+ if (!QType.isNull())
+ T = QType.getTypePtr();
+ } else
+ T = T->getPointeeOrArrayElementType();
+ }
+
+ return T;
+}
+
+bool isLiteralType(QualType QT, const ASTContext &Ctx,
+ const bool ConservativeLiteralType);
+
+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 = unwrapPointee(T);
+ if (!T)
+ return false;
+
+ assert(!T->isPointerOrReferenceType());
+
+ if (T->isIncompleteType() || T->isIncompleteArrayType())
+ return false;
+
+ if (T->isLiteralType(Ctx))
+ return true;
+
+ if (const auto *Rec = T->getAsCXXRecordDecl()) {
+ if (llvm::any_of(Rec->ctors(), [](const CXXConstructorDecl *Ctor) {
+ return !Ctor->isCopyOrMoveConstructor() &&
+ Ctor->isConstexprSpecified();
+ }))
+ return false;
+
+ for (const CXXBaseSpecifier Base : Rec->bases()) {
+ if (!isLiteralType(Base.getType(), Ctx, ConservativeLiteralType))
+ return false;
+ }
+ }
+
+ if (const Type *ArrayElementType = T->getArrayElementTypeNoTypeQual())
+ return isLiteralType(ArrayElementType, Ctx, ConservativeLiteralType);
+
+ return false;
+}
+
+bool isLiteralType(QualType QT, const ASTContext &Ctx,
+ const bool ConservativeLiteralType) {
+ return isLiteralType(QT.getTypePtr(), Ctx, ConservativeLiteralType);
+}
+
+bool satisfiesProperties11(
+ const FunctionDecl *FDecl, ASTContext &Ctx,
+ const bool ConservativeLiteralType,
+ const bool AddConstexprToMethodOfClassWithoutConstexprConstructor) {
+ if (FDecl->isConstexprSpecified()) {
+ return true;
+ }
+ const LangOptions LO = Ctx.getLangOpts();
+ const CXXMethodDecl *Method = llvm::dyn_cast<CXXMethodDecl>(FDecl);
+ if (Method && !Method->isStatic() &&
+ !Method->getParent()->hasConstexprNonCopyMoveConstructor() &&
+ !AddConstexprToMethodOfClassWithoutConstexprConstructor)
+ return false;
+
+ if (Method &&
+ (Method->isVirtual() ||
+ !match(cxxMethodDecl(hasBody(cxxTryStmt())), *Method, Ctx).empty()))
+ return false;
+
+ if (const auto *Ctor = llvm::dyn_cast<CXXConstructorDecl>(FDecl);
+ Ctor && (!satisfiesConstructorPropertiesUntil20(Ctor, Ctx) ||
+ llvm::any_of(Ctor->getParent()->bases(),
+ [](const CXXBaseSpecifier &Base) {
+ return Base.isVirtual();
+ })))
+ return false;
+
+ if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(FDecl);
+ Dtor && !Dtor->isTrivial())
+ return false;
+
+ if (!isLiteralType(FDecl->getReturnType(), Ctx, ConservativeLiteralType))
+ return false;
+
+ for (const ParmVarDecl *Param : FDecl->parameters())
+ if (!isLiteralType(Param->getType(), Ctx, ConservativeLiteralType))
+ return false;
+
+ class Visitor11 : public clang::RecursiveASTVisitor<Visitor11> {
+ public:
+ using Base = clang::RecursiveASTVisitor<Visitor11>;
+ bool shouldVisitImplicitCode() const { return true; }
+
+ Visitor11(ASTContext &Ctx, bool ConservativeLiteralType)
+ : Ctx(Ctx), ConservativeLiteralType(ConservativeLiteralType) {}
+
+ bool WalkUpFromNullStmt(NullStmt *) {
+ Possible = false;
+ return true;
+ }
+ bool WalkUpFromDeclStmt(DeclStmt *DS) {
+ for (const Decl *D : DS->decls())
+ if (!llvm::isa<StaticAssertDecl, TypedefNameDecl, UsingDecl,
+ UsingDirectiveDecl>(D)) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ bool WalkUpFromExpr(Expr *) { return true; }
+ bool WalkUpFromCompoundStmt(CompoundStmt *S) {
+ for (const DynTypedNode &Node : Ctx.getParents(*S))
+ if (Node.get<FunctionDecl>() != nullptr)
+ return true;
+
+ Possible = false;
+ return false;
+ }
+ bool WalkUpFromStmt(Stmt *) {
+ Possible = false;
+ return false;
+ }
+
+ bool WalkUpFromReturnStmt(ReturnStmt *) {
+ ++NumReturns;
+ if (NumReturns != 1U) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ bool WalkUpFromCastExpr(CastExpr *CE) {
+ if (llvm::is_contained(
+ {
+ CK_LValueBitCast,
+ CK_IntegralToPointer,
+ CK_PointerToIntegral,
+ },
+ CE->getCastKind())) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ bool TraverseCXXDynamicCastExpr(CXXDynamicCastExpr *) {
+ Possible = false;
+ return false;
+ }
+
+ bool TraverseCXXReinterpretCastExpr(CXXReinterpretCastExpr *) {
+ Possible = false;
+ return false;
+ }
+
+ bool TraverseType(QualType QT) {
+ if (QT.isNull())
+ return true;
+ if (!isLiteralType(QT, Ctx, ConservativeLiteralType)) {
+ Possible = false;
+ return false;
+ }
+ return Base::TraverseType(QT);
+ }
+
+ bool WalkUpFromCXXConstructExpr(CXXConstructExpr *CE) {
+ if (const auto *Ctor = CE->getConstructor();
+ Ctor && !Ctor->isConstexprSpecified()) {
+ Possible = false;
+ return false;
+ }
+
+ return true;
+ }
+ bool WalkUpFromCallExpr(CallExpr *CE) {
+ if (const auto *FDecl =
+ llvm::dyn_cast_if_present<FunctionDecl>(CE->getCalleeDecl());
+ FDecl && !FDecl->isConstexprSpecified()) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ bool TraverseCXXNewExpr(CXXNewExpr *) {
+ Possible = false;
+ return false;
+ }
+
+ ASTContext &Ctx;
+ const bool ConservativeLiteralType;
+ bool Possible = true;
+ size_t NumReturns = 0;
+ };
+
+ Visitor11 V{Ctx, ConservativeLiteralType};
+ V.TraverseDecl(const_cast<FunctionDecl *>(FDecl));
+ if (!V.Possible)
+ return false;
+
+ return true;
+}
+
+// The only difference between C++14 and C++17 is that `constexpr` lambdas
+// can be used in C++17.
+bool satisfiesProperties1417(
+ const FunctionDecl *FDecl, ASTContext &Ctx,
+ const bool ConservativeLiteralType,
+ const bool AddConstexprToMethodOfClassWithoutConstexprConstructor) {
+ if (FDecl->isConstexprSpecified())
+ return true;
+
+ const LangOptions LO = Ctx.getLangOpts();
+ const CXXMethodDecl *Method = llvm::dyn_cast<CXXMethodDecl>(FDecl);
+ if (Method && !Method->isStatic() &&
+ !Method->getParent()->hasConstexprNonCopyMoveConstructor() &&
+ !AddConstexprToMethodOfClassWithoutConstexprConstructor)
+ return false;
+
+ if (Method && Method->isVirtual())
+ return false;
+
+ if (llvm::isa<CXXConstructorDecl>(FDecl) &&
+ llvm::any_of(
+ Method->getParent()->bases(),
+ [](const CXXBaseSpecifier &Base) { return Base.isVirtual(); }))
+ return false;
+
+ if (!isLiteralType(FDecl->getReturnType(), Ctx, ConservativeLiteralType))
+ return false;
+
+ for (const ParmVarDecl *Param : FDecl->parameters())
+ if (!isLiteralType(Param->getType(), Ctx, ConservativeLiteralType))
+ return false;
+
+ class Visitor14 : public clang::RecursiveASTVisitor<Visitor14> {
+ public:
+ using Base = clang::RecursiveASTVisitor<Visitor14>;
+ bool shouldVisitImplicitCode() const { return true; }
+
+ Visitor14(bool CXX17, ASTContext &Ctx, bool ConservativeLiteralType,
+ bool AddConstexprToMethodOfClassWithoutConstexprConstructor)
+ : CXX17(CXX17), Ctx(Ctx),
+ ConservativeLiteralType(ConservativeLiteralType),
+ AddConstexprToMethodOfClassWithoutConstexprConstructor(
+ AddConstexprToMethodOfClassWithoutConstexprConstructor) {}
+
+ bool TraverseGotoStmt(GotoStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseLabelStmt(LabelStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseCXXTryStmt(CXXTryStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseGCCAsmStmt(GCCAsmStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseMSAsmStmt(MSAsmStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseDecompositionDecl(DecompositionDecl * /*DD*/) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseVarDecl(VarDecl *VD) {
+ const auto StorageDur = VD->getStorageDuration();
+ Possible = VD->hasInit() &&
+ isLiteralType(VD->getType(), VD->getASTContext(),
+ ConservativeLiteralType) &&
+ (StorageDur != StorageDuration::SD_Static &&
+ StorageDur != StorageDuration::SD_Thread);
+ return Possible && Base::TraverseVarDecl(VD);
+ }
+ bool TraverseLambdaExpr(LambdaExpr *LE) {
+ if (CXX17) {
+ Possible = satisfiesProperties1417(
+ LE->getCallOperator(), Ctx, ConservativeLiteralType,
+ AddConstexprToMethodOfClassWithoutConstexprConstructor);
+ return Possible;
+ }
+ Possible = false;
+ return false;
+ }
+ bool TraverseCXXNewExpr(CXXNewExpr *) {
+ Possible = false;
+ return false;
+ }
+
+ bool TraverseDeclRefExpr(DeclRefExpr *DRef) {
+ if (const auto *D = llvm::dyn_cast_if_present<VarDecl>(DRef->getDecl());
+ D && !D->isLocalVarDeclOrParm() && D->hasGlobalStorage()) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ bool WalkUpFromCastExpr(CastExpr *CE) {
+ if (llvm::is_contained(
+ {
+ CK_LValueBitCast,
+ CK_IntegralToPointer,
+ CK_PointerToIntegral,
+ },
+ CE->getCastKind())) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ bool TraverseCXXDynamicCastExpr(CXXDynamicCastExpr *) {
+ Possible = false;
+ return false;
+ }
+
+ bool TraverseCXXReinterpretCastExpr(CXXReinterpretCastExpr *) {
+ Possible = false;
+ return false;
+ }
+
+ const bool CXX17;
+ bool Possible = true;
+ ASTContext &Ctx;
+ const bool ConservativeLiteralType;
+ const bool AddConstexprToMethodOfClassWithoutConstexprConstructor;
+ };
+
+ Visitor14 V{Ctx.getLangOpts().CPlusPlus17 != 0, Ctx, ConservativeLiteralType,
+ AddConstexprToMethodOfClassWithoutConstexprConstructor};
+ V.TraverseDecl(const_cast<FunctionDecl *>(FDecl));
+ if (!V.Possible)
+ return false;
+
+ if (const auto *Ctor = llvm::dyn_cast<CXXConstructorDecl>(FDecl);
+ Ctor && !satisfiesConstructorPropertiesUntil20(Ctor, Ctx))
+ return false;
+
+ if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(FDecl);
+ Dtor && !Dtor->isTrivial())
+ return false;
+
+ class BodyVisitor : public clang::RecursiveASTVisitor<BodyVisitor> {
+ public:
+ using Base = clang::RecursiveASTVisitor<BodyVisitor>;
+ bool shouldVisitImplicitCode() const { return true; }
+
+ explicit BodyVisitor(ASTContext &Ctx, bool ConservativeLiteralType)
+ : Ctx(Ctx), ConservativeLiteralType(ConservativeLiteralType) {}
+
+ bool TraverseType(QualType QT) {
+ if (QT.isNull())
+ return true;
+ if (!isLiteralType(QT, Ctx, ConservativeLiteralType)) {
+ Possible = false;
+ return false;
+ }
+ return Base::TraverseType(QT);
+ }
+
+ bool WalkUpFromCXXConstructExpr(CXXConstructExpr *CE) {
+ if (const auto *Ctor = CE->getConstructor();
+ Ctor && !Ctor->isConstexprSpecified()) {
+ Possible = false;
+ return false;
+ }
+
+ return true;
+ }
+ bool WalkUpFromCallExpr(CallExpr *CE) {
+ if (const auto *FDecl =
+ llvm::dyn_cast_if_present<FunctionDecl>(CE->getCalleeDecl());
+ FDecl && !FDecl->isConstexprSpecified()) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ bool TraverseCXXNewExpr(CXXNewExpr *) {
+ Possible = false;
+ return false;
+ }
+
+ ASTContext &Ctx;
+ const bool ConservativeLiteralType;
+ bool Possible = true;
+ };
+
+ if (FDecl->hasBody() && ConservativeLiteralType) {
+ BodyVisitor Visitor(Ctx, ConservativeLiteralType);
+ Visitor.TraverseStmt(FDecl->getBody());
+ if (!Visitor.Possible)
+ return false;
+ }
+ return true;
+}
+
+bool satisfiesProperties20(
+ const FunctionDecl *FDecl, ASTContext &Ctx,
+ const bool ConservativeLiteralType,
+ const bool AddConstexprToMethodOfClassWithoutConstexprConstructor) {
+ if (FDecl->isConstexprSpecified()) {
+ return true;
+ }
+ const LangOptions LO = Ctx.getLangOpts();
+ const CXXMethodDecl *Method = llvm::dyn_cast<CXXMethodDecl>(FDecl);
+ if (Method && !Method->isStatic() &&
+ !Method->getParent()->hasConstexprNonCopyMoveConstructor() &&
+ !AddConstexprToMethodOfClassWithoutConstexprConstructor)
+ return false;
+
+ if (FDecl->hasBody() && llvm::isa<CoroutineBodyStmt>(FDecl->getBody()))
+ return false;
+
+ if ((llvm::isa<CXXConstructorDecl>(FDecl) ||
+ llvm::isa<CXXDestructorDecl>(FDecl)) &&
+ llvm::any_of(
+ Method->getParent()->bases(),
+ [](const CXXBaseSpecifier &Base) { return Base.isVirtual(); }))
+ return false;
+
+ if (!isLiteralType(FDecl->getReturnType(), Ctx, ConservativeLiteralType))
+ return false;
+
+ for (const ParmVarDecl *Param : FDecl->parameters())
+ if (!isLiteralType(Param->getType(), Ctx, ConservativeLiteralType))
+ return false;
+
+ class Visitor20 : public clang::RecursiveASTVisitor<Visitor20> {
+ public:
+ bool shouldVisitImplicitCode() const { return true; }
+
+ Visitor20(bool ConservativeLiteralType)
+ : ConservativeLiteralType(ConservativeLiteralType) {}
+
+ bool TraverseGotoStmt(GotoStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseLabelStmt(LabelStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseCXXTryStmt(CXXTryStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseGCCAsmStmt(GCCAsmStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseMSAsmStmt(MSAsmStmt *) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseDecompositionDecl(DecompositionDecl * /*DD*/) {
+ Possible = false;
+ return false;
+ }
+ bool TraverseVarDecl(VarDecl *VD) {
+ const auto StorageDur = VD->getStorageDuration();
+ Possible = isLiteralType(VD->getType(), VD->getASTContext(),
+ ConservativeLiteralType) &&
+ (StorageDur != StorageDuration::SD_Static &&
+ StorageDur != StorageDuration::SD_Thread);
+ return Possible;
+ }
+
+ bool WalkUpFromCastExpr(CastExpr *CE) {
+ if (llvm::is_contained(
+ {
+ CK_LValueBitCast,
+ CK_IntegralToPointer,
+ CK_PointerToIntegral,
+ },
+ CE->getCastKind())) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ bool TraverseCXXReinterpretCastExpr(CXXReinterpretCastExpr *) {
+ Possible = false;
+ return false;
+ }
+
+ bool Possible = true;
+ bool ConservativeLiteralType;
+ };
+
+ Visitor20 V{ConservativeLiteralType};
+ V.TraverseDecl(const_cast<FunctionDecl *>(FDecl));
+ if (!V.Possible)
+ return false;
+
+ if (const auto *Ctor = llvm::dyn_cast<CXXConstructorDecl>(FDecl))
+ satisfiesConstructorPropertiesUntil20(Ctor, Ctx);
+
+ if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(FDecl);
+ Dtor && !Dtor->isTrivial())
+ return false;
+
+ class BodyVisitor : public clang::RecursiveASTVisitor<BodyVisitor> {
+ public:
+ using Base = clang::RecursiveASTVisitor<BodyVisitor>;
+ bool shouldVisitImplicitCode() const { return true; }
+
+ explicit BodyVisitor(const ASTContext &Ctx, bool ConservativeLiteralType)
+ : Ctx(Ctx), LO(Ctx.getLangOpts()),
+ ConservativeLiteralType(ConservativeLiteralType) {}
+
+ bool TraverseType(QualType QT) {
+ if (QT.isNull())
+ return true;
+ if (!isLiteralType(QT, Ctx, ConservativeLiteralType)) {
+ Possible = false;
+ return false;
+ }
+ return Base::TraverseType(QT);
+ }
+
+ bool WalkUpFromCXXConstructExpr(CXXConstructExpr *CE) {
+ if (const auto *Ctor = CE->getConstructor();
+ Ctor && !Ctor->isConstexprSpecified()) {
+ Possible = false;
+ return false;
+ }
+
+ return true;
+ }
+ bool WalkUpFromCallExpr(CallExpr *CE) {
+ if (const auto *FDecl =
+ llvm::dyn_cast_if_present<FunctionDecl>(CE->getCalleeDecl());
+ FDecl && !FDecl->isConstexprSpecified()) {
+ Possible = false;
+ return false;
+ }
+ return true;
+ }
+
+ const ASTContext &Ctx;
+ const LangOptions &LO;
+ const bool ConservativeLiteralType;
+ bool Possible = true;
+ };
+
+ if (FDecl->hasBody() && ConservativeLiteralType) {
+ BodyVisitor Visitor(Ctx, ConservativeLiteralType);
+ Visitor.TraverseStmt(FDecl->getBody());
+ if (!Visitor.Possible)
+ return false;
+ }
+ return true;
+}
+
+bool satisfiesProperties2326(
+ const FunctionDecl *FDecl, ASTContext &Ctx,
+ const bool AddConstexprToMethodOfClassWithoutConstexprConstructor) {
+ if (FDecl->isConstexprSpecified()) {
+ return true;
+ }
+ const LangOptions LO = Ctx.getLangOpts();
+ const CXXMethodDecl *Method = llvm::dyn_cast<CXXMethodDecl>(FDecl);
+ if (Method && !Method->isStatic() &&
+ !Method->getParent()->hasConstexprNonCopyMoveConstructor() &&
+ !AddConstexprToMethodOfClassWithoutConstexprConstructor)
+ return false;
+
+ if (FDecl->hasBody() && llvm::isa<CoroutineBodyStmt>(FDecl->getBody()))
+ return false;
+
+ if ((llvm::isa<CXXConstructorDecl>(FDecl) ||
+ llvm::isa<CXXDestructorDecl>(FDecl)) &&
+ llvm::any_of(
+ Method->getParent()->bases(),
+ [](const CXXBaseSpecifier &Base) { return Base.isVirtual(); }))
+ return false;
+ return true;
+}
+
+// FIXME: add test for uncalled lambda that throws, and called lambda that
+// throws
+// FIXME: fix CXX23 allowing decomposition decls, but it is only a feature since
+// CXX26
+AST_MATCHER_P2(FunctionDecl, satisfiesProperties, bool, ConservativeLiteralType,
+ bool, AddConstexprToMethodOfClassWithoutConstexprConstructor) {
+ ASTContext &Ctx = Finder->getASTContext();
+ const LangOptions LO = Ctx.getLangOpts();
+
+ if (LO.CPlusPlus26) {
+ return satisfiesProperties2326(
+ &Node, Ctx, AddConstexprToMethodOfClassWithoutConstexprConstructor);
+ }
+ if (LO.CPlusPlus23) {
+ return satisfiesProperties2326(
+ &Node, Ctx, AddConstexprToMethodOfClassWithoutConstexprConstructor);
+ }
+ if (LO.CPlusPlus20) {
+ return satisfiesProperties20(
+ &Node, Ctx, ConservativeLiteralType,
+ AddConstexprToMethodOfClassWithoutConstexprConstructor);
+ }
+ if (LO.CPlusPlus17) {
+ return satisfiesProperties1417(
+ &Node, Ctx, ConservativeLiteralType,
+ AddConstexprToMethodOfClassWithoutConstexprConstructor);
+ }
+ if (LO.CPlusPlus14) {
+ return satisfiesProperties1417(
+ &Node, Ctx, ConservativeLiteralType,
+ AddConstexprToMethodOfClassWithoutConstexprConstructor);
+ }
+ if (LO.CPlusPlus11)
+ return satisfiesProperties11(
+ &Node, Ctx, ConservativeLiteralType,
+ AddConstexprToMethodOfClassWithoutConstexprConstructor);
+
+ return false;
+}
+
+AST_MATCHER_P(VarDecl, satisfiesVariableProperties, bool,
+ ConservativeLiteralType) {
+ ASTContext &Ctx = Finder->getASTContext();
+ const LangOptions LO = Ctx.getLangOpts();
+
+ const QualType QT = Node.getType();
+ const Type *T = QT.getTypePtr();
+ if (!T)
+ return false;
+
+ if (!isLiteralType(T, Ctx, ConservativeLiteralType))
+ return false;
+
+ const bool IsDeclaredInsideConstexprFunction = std::invoke([&Node]() {
+ const auto *Func = llvm::dyn_cast<FunctionDecl>(Node.getDeclContext());
+ if (!Func)
+ return false;
+ return !Func->isConstexpr();
+ });
+
+ if (!Finder->getASTContext().getLangOpts().CPlusPlus23 &&
+ Node.isStaticLocal() && IsDeclaredInsideConstexprFunction)
+ return false;
+
+ if (!Finder->getASTContext().getLangOpts().CPlusPlus20)
+ return true;
+
+ const auto *RDecl = T->getAsCXXRecordDecl();
+ const auto *const ArrayOrPtrElement = T->getPointeeOrArrayElementType();
+ if (ArrayOrPtrElement)
+ RDecl = ArrayOrPtrElement->getAsCXXRecordDecl();
+
+ if (RDecl && (!RDecl->hasDefinition() || !RDecl->hasConstexprDestructor()))
+ return false;
+
+ return true;
+}
+} // namespace
+
+void UseConstexprCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(
+ functionDecl(
+ isDefinition(),
+ unless(anyOf(isConstexpr(), isImplicit(), hasExternalFormalLinkage(),
+ isInMacro(), isMain(), isInStdNamespace(),
+ isExpansionInSystemHeader(), isExternC())),
+ locationPermitsConstexpr(), allRedeclsInSameFile(),
+ satisfiesProperties(
+ ConservativeLiteralType,
+ AddConstexprToMethodOfClassWithoutConstexprConstructor))
+ .bind("func"),
+ this);
+
+ Finder->addMatcher(
+ functionDecl(isConstexpr(), isImplicit(), unless(isConstexprSpecified()),
+ unless(anyOf(isInStdNamespace(), isExpansionInSystemHeader(),
+ isInMacro())),
+ allRedeclsInSameFile())
+ .bind("func"),
+ this);
+
+ Finder->addMatcher(
+ varDecl(
+ unless(anyOf(parmVarDecl(), isImplicit(), isInStdNamespace(),
+ isExpansionInSystemHeader(), isConstexpr(), isExternC(),
+ hasExternalFormalLinkage(), isInMacro())),
+ hasNoRedecl(), hasType(qualType(isConstQualified())),
+ satisfiesVariableProperties(ConservativeLiteralType),
+ hasInitializer(expr(isCXX11ConstantExpr())))
+ .bind("var"),
+ this);
+}
+
+void UseConstexprCheck::check(const MatchFinder::MatchResult &Result) {
+ constexpr const auto MaybeResolveToTemplateDecl =
+ [](const FunctionDecl *Func) {
+ if (Func && Func->isTemplateInstantiation())
+ Func = Func->getTemplateInstantiationPattern();
+ return Func;
+ };
+
+ if (const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func")) {
+ Func = MaybeResolveToTemplateDecl(Func);
+ if (Func)
+ Functions.insert(Func);
+ return;
+ }
+
+ if (const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var")) {
+ if (const VarDecl *VarTemplate = Var->getTemplateInstantiationPattern())
+ Var = VarTemplate;
+
+ VariableMapping.insert({Var, MaybeResolveToTemplateDecl(
+ llvm::dyn_cast_if_present<FunctionDecl>(
+ Var->getDeclContext()))});
+ return;
+ }
+}
+
+void UseConstexprCheck::onEndOfTranslationUnit() {
+ for (const FunctionDecl *Func : Functions) {
+ const SourceRange R =
+ SourceRange(Func->getInnerLocStart(), Func->getLocation());
+ auto Diag =
+ diag(Func->getLocation(), "function %0 can be declared 'constexpr'")
+ << Func << R;
+
+ for (const Decl *D : Func->redecls())
+ if (const auto *FDecl = llvm::dyn_cast<FunctionDecl>(D))
+ Diag << FixItHint::CreateInsertion(FDecl->getInnerLocStart(),
+ "constexpr ");
+ }
+ for (const auto &[Var, FuncCtx] : VariableMapping) {
+ if (FuncCtx && getLangOpts().CPlusPlus23 && Var->isStaticLocal() &&
+ Functions.contains(FuncCtx))
+ continue;
+ const SourceRange R =
+ SourceRange(Var->getInnerLocStart(), Var->getLocation());
+ auto Diag =
+ diag(Var->getLocation(), "variable %0 can be declared 'constexpr'")
+ << Var << R
+ << FixItHint::CreateInsertion(Var->getInnerLocStart(), "constexpr ");
+ if (const std::optional<Token> ConstToken =
+ utils::lexer::getQualifyingToken(
+ tok::TokenKind::kw_const,
+ CharSourceRange::getTokenRange(Var->getSourceRange()),
+ Var->getASTContext(),
+ Var->getASTContext().getSourceManager())) {
+ Diag << FixItHint::CreateRemoval(ConstToken->getLocation());
+ }
+ }
+
+ Functions.clear();
+ VariableMapping.clear();
+}
+
+UseConstexprCheck::UseConstexprCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ ConservativeLiteralType(Options.get("ConservativeLiteralType", true)),
+ AddConstexprToMethodOfClassWithoutConstexprConstructor(Options.get(
+ "AddConstexprToMethodOfClassWithoutConstexprConstructor", false)) {}
+void UseConstexprCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "ConservativeLiteralType", ConservativeLiteralType);
+ Options.store(Opts, "AddConstexprToMethodOfClassWithoutConstexprConstructor",
+ AddConstexprToMethodOfClassWithoutConstexprConstructor);
+}
+} // namespace clang::tidy::misc
diff --git a/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.h b/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.h
new file mode 100644
index 0000000000000..9a193e9f56518
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.h
@@ -0,0 +1,43 @@
+//===--- UseUseConstexprCheck.h - clang-tidy --------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USECONSTEXPRCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USECONSTEXPRCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+
+namespace clang::tidy::misc {
+
+/// Find functions and variables that can be declared 'constexpr'.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc/use-constexpr.html
+class UseConstexprCheck : public ClangTidyCheck {
+public:
+ UseConstexprCheck(StringRef Name, ClangTidyContext *Context);
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus11;
+ }
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void onEndOfTranslationUnit() override;
+
+private:
+ const bool ConservativeLiteralType;
+ const bool AddConstexprToMethodOfClassWithoutConstexprConstructor;
+ llvm::SmallPtrSet<const FunctionDecl *, 32> Functions;
+ llvm::DenseMap<const VarDecl *, const FunctionDecl *> VariableMapping;
+};
+
+} // namespace clang::tidy::misc
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USECONSTEXPRCHECK_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 5098582d0c42b..9e6f99e01b7b0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -277,6 +277,7 @@ Clang-Tidy Checks
:doc:`misc-unused-parameters <misc/unused-parameters>`, "Yes"
:doc:`misc-unused-using-decls <misc/unused-using-decls>`, "Yes"
:doc:`misc-use-anonymous-namespace <misc/use-anonymous-namespace>`,
+ :doc:`misc-use-constexpr <misc/use-constexpr>`, "Yes"
:doc:`misc-use-internal-linkage <misc/use-internal-linkage>`, "Yes"
:doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes"
:doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/use-constexpr.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/use-constexpr.rst
new file mode 100644
index 0000000000000..8205ab0e014d6
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/misc/use-constexpr.rst
@@ -0,0 +1,40 @@
+.. title:: clang-tidy - misc-use-constexpr
+
+misc-use-constexpr
+==================
+
+Find functions and variables that can be declared 'constexpr'.
+
+The check analyses any function and variable according to the rules defined
+for the language version that the code is compiled with.
+Changing to a newer language standard may therefore offer additional opportunity
+to declare a function or variable as ``constexpr``.
+
+Options
+-------
+
+.. option:: ConservativeLiteralType
+
+ With this option enabled, only literal types that can be constructed at
+ compile-time are considered to supoprt ``constexpr``.
+
+ .. code-block:: c++
+
+ struct NonLiteral{
+ NonLiteral();
+ ~NonLiteral();
+ int &ref;
+ };
+
+ This type is a literal type, but can not be constructed at compile-time,
+ so with `ConservativeLiteralType` equal to `true`, variables or funtions
+ with this type are not considered to support ``constexpr``. Default is
+ `true`.
+
+.. option:: AddConstexprToMethodOfClassWithoutConstexprConstructor
+
+ While a function of a class or struct could be declared ``constexpr``, when
+ the class itself can never be constructed at compile-time, then adding
+ ``constexpr`` to a member function is superfluous. This option controls if
+ ``constexpr`` should be added anyways. Default is ``false``.
+
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr-cxx20.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr-cxx20.cpp
new file mode 100644
index 0000000000000..bae1b87505bbc
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr-cxx20.cpp
@@ -0,0 +1,36 @@
+// RUN: %check_clang_tidy -std=c++20 %s misc-use-constexpr %t
+
+namespace std {
+template <typename T = void>
+struct coroutine_handle {
+ static constexpr coroutine_handle from_address(void* addr) {
+ return {};
+ }
+};
+
+struct always_suspend {
+ bool await_ready() const noexcept;
+ bool await_resume() const noexcept;
+ template <typename T>
+ bool await_suspend(coroutine_handle<T>) const noexcept;
+};
+
+template <typename T>
+struct coroutine_traits {
+ using promise_type = T::promise_type;
+};
+} // namespace std
+
+struct generator {
+ struct promise_type {
+ void return_value(int v);
+ std::always_suspend yield_value(int&&);
+ std::always_suspend initial_suspend() const noexcept;
+ std::always_suspend final_suspend() const noexcept;
+ void unhandled_exception();
+ generator get_return_object();
+ };
+};
+
+
+generator f25() { co_return 10; }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr.cpp
new file mode 100644
index 0000000000000..02496be16a007
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr.cpp
@@ -0,0 +1,562 @@
+// RUN: %check_clang_tidy -std=c++11 -check-suffix=11 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++14 -check-suffix=11,14 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++17 -check-suffix=11,14,17 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++20 -check-suffix=11,14,17,20 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=11,14,17,20,23 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
+
+// RUN: %check_clang_tidy -std=c++11 -check-suffix=11,11-CLT %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++14 -check-suffix=11,11-CLT,14,14-CLT %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++17 -check-suffix=11,11-CLT,14,14-CLT,17,17-CLT %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++20 -check-suffix=11,11-CLT,14,14-CLT,17,17-CLT,20,20-CLT %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=11,14,17,20,23 %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+
+namespace {
+namespace my {
+ struct point {
+ constexpr point() {}
+ int get_x() const { return x; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:9: warning: function 'get_x' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr int get_x() const { return x; }
+ int x;
+ int y;
+ };
+
+ struct point2 {
+ point2();
+ int get_x() const { return x; }
+ int x;
+ };
+} // namespace my
+} // namespace
+
+namespace function {
+ struct Empty {};
+
+ struct Base {
+ virtual void virt() = 0;
+ };
+ struct Derived : Base {
+ Derived() {}
+ void virt() override {}
+ };
+
+ static void f1() {}
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static void f1() {}
+
+ static int f2() { return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f2() { return 0; }
+
+ static int f3(int x) { return x; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f3(int x) { return x; }
+
+ static int f4(Empty x) { return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f4(Empty x) { return 0; }
+
+ static int f5(Empty x) { return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f5(Empty x) { return 0; }
+
+ static int f6(Empty x) { ; return 0; }
+ // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-14: constexpr static int f6(Empty x) { ; return 0; }
+
+ static int f7(Empty x) { static_assert(0 == 0, ""); return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f7(Empty x) { static_assert(0 == 0, ""); return 0; }
+
+ static int f8(Empty x) { using my_int = int; return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f8(Empty x) { using my_int = int; return 0; }
+
+ static int f9(Empty x) { using my::point; return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f9(Empty x) { using my::point; return 0; }
+
+ static int f10(Empty x) { return 10; return 0; }
+ // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-14: constexpr static int f10(Empty x) { return 10; return 0; }
+
+ static int f11(Empty x) { if (true) return 10; return 0; }
+ // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-14: constexpr static int f11(Empty x) { if (true) return 10; return 0; }
+
+ static int f12(Empty x) { label: ; goto label; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f12(Empty x) { label: ; goto label; return 0; }
+ static int f13(Empty x) { try { throw 0; } catch(int) {}; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f13(Empty x) { try { throw 0; } catch(int) {}; return 0; }
+ static int f14(Empty x) { asm ("mov %rax, %rax"); }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f14(Empty x) { asm ("mov %rax, %rax"); }
+ static int f15(Empty x) { int y; return 0; }
+ // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-20: constexpr static int f15(Empty x) { int y; return 0; }
+ static int f16(Empty x) { static int y = 0; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f16(Empty x) { static int y = 0; return 0; }
+ static int f17(Empty x) { thread_local int y = 0; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f17(Empty x) { thread_local int y = 0; return 0; }
+ static int f18(Empty x) { [](){ label: ; goto label; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f18(Empty x) { [](){ label: ; goto label; return 0; }; return 0; }
+ static int f19(Empty x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f19(Empty x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
+ static int f20(Empty x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f20(Empty x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
+ static int f21(Empty x) { [](){ int y; return 0; }; return 0; }
+ // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-20: constexpr static int f21(Empty x) { [](){ int y; return 0; }; return 0; }
+ static int f22(Empty x) { [](){ static int y = 0; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f22(Empty x) { [](){ static int y = 0; return 0; }; return 0; }
+ static int f23(Empty x) { [](){ thread_local int y = 0; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f23(Empty x) { [](){ thread_local int y = 0; return 0; }; return 0; }
+
+ static int f24(Empty x) { return [](){ return 0; }(); }
+ // CHECK-MESSAGES-17: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-17: constexpr static int f24(Empty x) { return [](){ return 0; }(); }
+
+ static int f25(Empty x) { new int; return 0; }
+ // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-20: constexpr static int f25(Empty x) { new int; return 0; }
+
+ struct Range0To10 {
+ struct iterator {
+ int operator*() const;
+ void operator++();
+ friend bool operator!=(const iterator&lhs, const iterator&rhs) { return lhs.i == rhs.i; }
+ int i;
+ };
+ iterator begin() const;
+ iterator end() const;
+ };
+ static int f26(Empty x) {
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f26(Empty x) {
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-14-CLT: constexpr static int f26(Empty x) {
+ auto R = Range0To10{};
+ for (const int i: R) { }
+ return 0;
+ }
+} // namespace function
+namespace function_non_literal {
+ struct NonLiteral{
+ NonLiteral();
+ ~NonLiteral();
+ int &ref;
+ };
+
+ struct Base {
+ virtual void virt() = 0;
+ };
+ struct Derived : Base {
+ Derived() {}
+ void virt() override {}
+ };
+
+ static void f1() {}
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static void f1() {}
+
+ static int f2() { return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f2() { return 0; }
+
+ static int f3(int x) { return x; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f3(int x) { return x; }
+
+ static int f4(NonLiteral x) { return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f4(NonLiteral x) { return 0; }
+
+ static int f5(NonLiteral x) { return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f5(NonLiteral x) { return 0; }
+
+ static int f6(NonLiteral x) { ; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f6(NonLiteral x) { ; return 0; }
+
+ static int f7(NonLiteral x) { static_assert(0 == 0, ""); return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f7(NonLiteral x) { static_assert(0 == 0, ""); return 0; }
+
+ static int f8(NonLiteral x) { using my_int = int; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f8(NonLiteral x) { using my_int = int; return 0; }
+
+ static int f9(NonLiteral x) { using my::point; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f9(NonLiteral x) { using my::point; return 0; }
+
+ static int f10(NonLiteral x) { return 10; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f10(NonLiteral x) { return 10; return 0; }
+
+ static int f11(NonLiteral x) { if (true) return 10; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f11(NonLiteral x) { if (true) return 10; return 0; }
+
+ static int f12(NonLiteral x) { label: ; goto label; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f12(NonLiteral x) { label: ; goto label; return 0; }
+ static int f13(NonLiteral x) { try { throw 0; } catch(int) {}; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f13(NonLiteral x) { try { throw 0; } catch(int) {}; return 0; }
+ static int f14(NonLiteral x) { asm ("mov %rax, %rax"); }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f14(NonLiteral x) { asm ("mov %rax, %rax"); }
+ static int f15(NonLiteral x) { int y; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f15(NonLiteral x) { int y; return 0; }
+ static int f16(NonLiteral x) { static int y = 0; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f16(NonLiteral x) { static int y = 0; return 0; }
+ static int f17(NonLiteral x) { thread_local int y = 0; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f17(NonLiteral x) { thread_local int y = 0; return 0; }
+ static int f18(NonLiteral x) { [](){ label: ; goto label; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f18(NonLiteral x) { [](){ label: ; goto label; return 0; }; return 0; }
+ static int f19(NonLiteral x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f19(NonLiteral x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
+ static int f20(NonLiteral x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f20(NonLiteral x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
+ static int f21(NonLiteral x) { [](){ int y; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f21(NonLiteral x) { [](){ int y; return 0; }; return 0; }
+ static int f22(NonLiteral x) { [](){ static int y = 0; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f22(NonLiteral x) { [](){ static int y = 0; return 0; }; return 0; }
+ static int f23(NonLiteral x) { [](){ thread_local int y = 0; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f23(NonLiteral x) { [](){ thread_local int y = 0; return 0; }; return 0; }
+
+ static int f24(NonLiteral x) { return [](){ return 0; }(); }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f24(NonLiteral x) { return [](){ return 0; }(); }
+
+ static int f25(NonLiteral x) { new int; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f25(NonLiteral x) { new int; return 0; }
+
+ struct Range0To10 {
+ struct iterator {
+ int operator*() const { return i; }
+ void operator++() { ++i; }
+ friend bool operator!=(const iterator&lhs, const iterator&rhs) { return lhs.i == rhs.i; }
+ int i;
+ };
+ iterator begin() const { return { 0 }; }
+ iterator end() const { return { 10 }; }
+ };
+ static int f26(NonLiteral x) {
+ auto R = Range0To10{};
+ for (const int i: R) { }
+ return 0;
+ }
+ // CHECK-MESSAGES-23: :[[@LINE-5]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f26(NonLiteral x) {
+} // namespace function_non_literal
+namespace function_non_literal_ref {
+ struct NonLiteral{
+ NonLiteral();
+ ~NonLiteral();
+ int &ref;
+ };
+
+ struct Base {
+ virtual void virt() = 0;
+ };
+ struct Derived : Base {
+ Derived() {}
+ void virt() override {}
+ };
+
+ static void f1() {}
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static void f1() {}
+
+ static int f2() { return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f2() { return 0; }
+
+ static int f3(int x) { return x; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int f3(int x) { return x; }
+
+ static int f4(NonLiteral& x) { return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f4(NonLiteral& x) { return 0; }
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11-CLT: constexpr static int f4(NonLiteral& x) { return 0; }
+
+ static int f5(NonLiteral& x) { return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f5(NonLiteral& x) { return 0; }
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11-CLT: constexpr static int f5(NonLiteral& x) { return 0; }
+
+ static int f6(NonLiteral& x) { ; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f6(NonLiteral& x) { ; return 0; }
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f6' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-14-CLT: constexpr static int f6(NonLiteral& x) { ; return 0; }
+
+ static int f7(NonLiteral& x) { static_assert(0 == 0, ""); return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f7(NonLiteral& x) { static_assert(0 == 0, ""); return 0; }
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f7' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11-CLT: constexpr static int f7(NonLiteral& x) { static_assert(0 == 0, ""); return 0; }
+
+ static int f8(NonLiteral& x) { using my_int = int; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f8(NonLiteral& x) { using my_int = int; return 0; }
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f8' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11-CLT: constexpr static int f8(NonLiteral& x) { using my_int = int; return 0; }
+
+ static int f9(NonLiteral& x) { using my::point; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f9(NonLiteral& x) { using my::point; return 0; }
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f9' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11-CLT: constexpr static int f9(NonLiteral& x) { using my::point; return 0; }
+
+ static int f10(NonLiteral& x) { return 10; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f10(NonLiteral& x) { return 10; return 0; }
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f10' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-14-CLT: constexpr static int f10(NonLiteral& x) { return 10; return 0; }
+
+ static int f11(NonLiteral& x) { if (true) return 10; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f11(NonLiteral& x) { if (true) return 10; return 0; }
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f11' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-14-CLT: constexpr static int f11(NonLiteral& x) { if (true) return 10; return 0; }
+
+ static int f12(NonLiteral& x) { label: ; goto label; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f12(NonLiteral& x) { label: ; goto label; return 0; }
+ static int f13(NonLiteral& x) { try { throw 0; } catch(int) {}; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f13(NonLiteral& x) { try { throw 0; } catch(int) {}; return 0; }
+ static int f14(NonLiteral& x) { asm ("mov %rax, %rax"); }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f14(NonLiteral& x) { asm ("mov %rax, %rax"); }
+ static int f15(NonLiteral& x) { int y; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f15(NonLiteral& x) { int y; return 0; }
+ // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f15' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-20-CLT: constexpr static int f15(NonLiteral& x) { int y; return 0; }
+ static int f16(NonLiteral& x) { static int y = 0; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f16(NonLiteral& x) { static int y = 0; return 0; }
+ static int f17(NonLiteral& x) { thread_local int y = 0; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f17(NonLiteral& x) { thread_local int y = 0; return 0; }
+ static int f18(NonLiteral& x) { [](){ label: ; goto label; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f18(NonLiteral& x) { [](){ label: ; goto label; return 0; }; return 0; }
+ static int f19(NonLiteral& x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f19(NonLiteral& x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
+ static int f20(NonLiteral& x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f20(NonLiteral& x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
+ static int f21(NonLiteral& x) { [](){ int y; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f21(NonLiteral& x) { [](){ int y; return 0; }; return 0; }
+ // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f21' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-20-CLT: constexpr static int f21(NonLiteral& x) { [](){ int y; return 0; }; return 0; }
+ static int f22(NonLiteral& x) { [](){ static int y = 0; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f22(NonLiteral& x) { [](){ static int y = 0; return 0; }; return 0; }
+ static int f23(NonLiteral& x) { [](){ thread_local int y = 0; return 0; }; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f23(NonLiteral& x) { [](){ thread_local int y = 0; return 0; }; return 0; }
+
+ static int f24(NonLiteral& x) { return [](){ return 0; }(); }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f24(NonLiteral& x) { return [](){ return 0; }(); }
+ // CHECK-MESSAGES-17-CLT: :[[@LINE-3]]:14: warning: function 'f24' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-17-CLT: constexpr static int f24(NonLiteral& x) { return [](){ return 0; }(); }
+
+ static int f25(NonLiteral& x) { new int; return 0; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f25(NonLiteral& x) { new int; return 0; }
+ // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f25' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-20-CLT: constexpr static int f25(NonLiteral& x) { new int; return 0; }
+
+ struct Range0To10 {
+ struct iterator {
+ int operator*() const { return i; }
+ void operator++() { ++i; }
+ friend bool operator!=(const iterator&lhs, const iterator&rhs) { return lhs.i == rhs.i; }
+ int i;
+ };
+ iterator begin() const { return { 0 }; }
+ iterator end() const { return { 10 }; }
+ };
+ static int f26(NonLiteral& x) {
+ auto R = Range0To10{};
+ for (const int i: R) { }
+ return 0;
+ }
+ // CHECK-MESSAGES-23: :[[@LINE-5]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f26(NonLiteral& x) {
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-7]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-14-CLT: constexpr static int f26(NonLiteral& x) {
+} // namespace function_non_literal_ref
+
+namespace {
+namespace variable {
+ namespace literal_type {
+ constexpr int f1() { return 0; }
+ int g1() { return 0; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:13: warning: function 'g1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr int g1() { return 0; }
+ static constexpr int A1 = 0;
+ static int B1 = 0;
+ static const int C1 = 0;
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:26: warning: variable 'C1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int C1 = 0;
+ static const int D1 = f1();
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:26: warning: variable 'D1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static int D1 = f1();
+ static const int E1 = g1();
+
+ template <typename T>
+ const T TemplatedVar1 = T{};
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: variable 'TemplatedVar1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr T TemplatedVar1 = T{};
+
+ void h1() {
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr void h1() {
+ int a1 = 0;
+ const int b1 = 1;
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:23: warning: variable 'b1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr int b1 = 1;
+ static int c1 = 2;
+ static const int d1 = 3;
+
+ static auto e1 = TemplatedVar1<int> + TemplatedVar1<unsigned int>;
+ }
+ } // namespace literal_type
+
+ namespace struct_type {
+ struct AStruct { int val; };
+ constexpr AStruct f2() { return {}; }
+ AStruct g2() { return {}; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: function 'g2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr AStruct g2() { return {}; }
+ static constexpr AStruct A2 = {};
+ static AStruct B2 = {};
+ static const AStruct C2 = {};
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'C2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static AStruct C2 = {};
+ static const AStruct D2 = f2();
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'D2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static AStruct D2 = f2();
+ static const AStruct E2 = g2();
+ void h2() {
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr void h2() {
+ AStruct a2{};
+ const AStruct b2{};
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:27: warning: variable 'b2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr AStruct b2{};
+ static AStruct c2{};
+ static const AStruct d2{};
+ }
+ } // namespace struct_type
+
+ namespace struct_type_non_literal {
+ struct AStruct { ~AStruct(); int val; };
+ AStruct g3() { return {}; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:17: warning: function 'g3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr AStruct g3() { return {}; }
+ static AStruct B3 = {};
+ static const AStruct C3 = {};
+ static const AStruct E3 = g3();
+
+ template <typename T>
+ const T TemplatedVar2 = T{};
+ template <typename T>
+ const T TemplatedVar2B = T{};
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: variable 'TemplatedVar2B' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr T TemplatedVar2B = T{};
+
+ void h3() {
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr void h3() {
+ AStruct a3{};
+ const AStruct b3{};
+ static AStruct c3{};
+ static const AStruct d3{};
+
+ static auto e1 = TemplatedVar2<AStruct>;
+ static auto f1 = TemplatedVar2B<AStruct>;
+ static auto g1 = TemplatedVar2B<int>;
+ }
+ } // namespace struct_type_non_literal
+
+ namespace struct_type_non_literal2 {
+ struct AStruct { volatile int Val; };
+ AStruct g4() { return {}; }
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:17: warning: function 'g4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr AStruct g4() { return {}; }
+ static AStruct B4 = {};
+ static const AStruct C4 = {};
+ static const AStruct E4 = g4();
+ void h4() {
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr void h4() {
+ AStruct a4{};
+ const AStruct b4{};
+ static AStruct c4{};
+ static const AStruct d4{};
+ }
+ } // namespace struct_type_non_literal2
+
+ namespace struct_type_non_literal3 {
+ struct AStruct { union { int val; float val5; }; };
+ constexpr AStruct f5() { return {}; }
+ AStruct g5() { return {}; }
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: function 'g5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr AStruct g5() { return {}; }
+ static constexpr AStruct A5 = {};
+ static AStruct B5 = {};
+ static const AStruct C5 = {};
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'C5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static AStruct C5 = {};
+ static const AStruct D5 = f5();
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'D5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr static AStruct D5 = f5();
+ static const AStruct E5 = g5();
+ void h5() {
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-23: constexpr void h5() {
+ AStruct a5{};
+ const AStruct b5{};
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:27: warning: variable 'b5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-FIXES-11: constexpr AStruct b5{};
+ static AStruct c5{};
+ static const AStruct d5{};
+ }
+ } // namespace struct_type_non_literal3
+} // namespace variable
+} // namespace
+
>From 4ab9aec691b66a3ad842a84b5d2f3c7c3f571c58 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Tue, 1 Jul 2025 18:42:34 +0200
Subject: [PATCH 02/11] rename to modernize-use-constexpr + review comments
---
.../clang-tidy/misc/CMakeLists.txt | 1 -
.../clang-tidy/misc/MiscTidyModule.cpp | 2 -
.../clang-tidy/modernize/CMakeLists.txt | 1 +
.../modernize/ModernizeTidyModule.cpp | 3 +
.../{misc => modernize}/UseConstexprCheck.cpp | 51 ++--
.../{misc => modernize}/UseConstexprCheck.h | 12 +-
clang-tools-extra/docs/ReleaseNotes.rst | 4 +
.../docs/clang-tidy/checks/list.rst | 2 +-
.../{misc => modernize}/use-constexpr.rst | 6 +-
.../use-constexpr-cxx20.cpp | 2 +-
.../{misc => modernize}/use-constexpr.cpp | 250 +++++++++---------
11 files changed, 170 insertions(+), 164 deletions(-)
rename clang-tools-extra/clang-tidy/{misc => modernize}/UseConstexprCheck.cpp (96%)
rename clang-tools-extra/clang-tidy/{misc => modernize}/UseConstexprCheck.h (78%)
rename clang-tools-extra/docs/clang-tidy/checks/{misc => modernize}/use-constexpr.rst (92%)
rename clang-tools-extra/test/clang-tidy/checkers/{misc => modernize}/use-constexpr-cxx20.cpp (92%)
rename clang-tools-extra/test/clang-tidy/checkers/{misc => modernize}/use-constexpr.cpp (78%)
diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
index b1630f72f4409..fd7affd22a463 100644
--- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt
@@ -19,7 +19,6 @@ set_target_properties(genconfusable PROPERTIES FOLDER "Clang Tools Extra/Sourceg
add_clang_library(clangTidyMiscModule STATIC
ConstCorrectnessCheck.cpp
- UseConstexprCheck.cpp
CoroutineHostileRAIICheck.cpp
DefinitionsInHeadersCheck.cpp
ConfusableIdentifierCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
index 38e829cc2004f..6ddebcbc0e152 100644
--- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp
@@ -31,7 +31,6 @@
#include "UnusedParametersCheck.h"
#include "UnusedUsingDeclsCheck.h"
#include "UseAnonymousNamespaceCheck.h"
-#include "UseConstexprCheck.h"
#include "UseInternalLinkageCheck.h"
namespace clang::tidy {
@@ -44,7 +43,6 @@ class MiscModule : public ClangTidyModule {
"misc-confusable-identifiers");
CheckFactories.registerCheck<ConstCorrectnessCheck>(
"misc-const-correctness");
- CheckFactories.registerCheck<UseConstexprCheck>("misc-use-constexpr");
CheckFactories.registerCheck<CoroutineHostileRAIICheck>(
"misc-coroutine-hostile-raii");
CheckFactories.registerCheck<DefinitionsInHeadersCheck>(
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 619a27b2f9bb6..db64050f8a9b9 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -30,6 +30,7 @@ add_clang_library(clangTidyModernizeModule STATIC
UnaryStaticAssertCheck.cpp
UseAutoCheck.cpp
UseBoolLiteralsCheck.cpp
+ UseConstexprCheck.cpp
UseConstraintsCheck.cpp
UseDefaultMemberInitCheck.cpp
UseDesignatedInitializersCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index fdf38bc4b6308..5afe0b0e1a69f 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -31,6 +31,7 @@
#include "UnaryStaticAssertCheck.h"
#include "UseAutoCheck.h"
#include "UseBoolLiteralsCheck.h"
+#include "UseConstexprCheck.h"
#include "UseConstraintsCheck.h"
#include "UseDefaultMemberInitCheck.h"
#include "UseDesignatedInitializersCheck.h"
@@ -76,6 +77,8 @@ class ModernizeModule : public ClangTidyModule {
CheckFactories.registerCheck<MinMaxUseInitializerListCheck>(
"modernize-min-max-use-initializer-list");
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
+ CheckFactories.registerCheck<UseConstexprCheck>(
+ "modernize-use-constexpr");
CheckFactories.registerCheck<UseDesignatedInitializersCheck>(
"modernize-use-designated-initializers");
CheckFactories.registerCheck<UseIntegerSignComparisonCheck>(
diff --git a/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
similarity index 96%
rename from clang-tools-extra/clang-tidy/misc/UseConstexprCheck.cpp
rename to clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
index e6874dcabedbb..cbfdde4f61920 100644
--- a/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
@@ -36,7 +36,7 @@
using namespace clang::ast_matchers;
-namespace clang::tidy::misc {
+namespace clang::tidy::modernize {
namespace {
AST_MATCHER(FunctionDecl, locationPermitsConstexpr) {
@@ -87,14 +87,16 @@ AST_MATCHER(Decl, allRedeclsInSameFile) {
AST_MATCHER(FunctionDecl, isConstexprSpecified) {
return Node.isConstexprSpecified();
}
+} // namespace
-bool satisfiesConstructorPropertiesUntil20(const CXXConstructorDecl *Ctor,
- ASTContext &Ctx) {
+static bool
+satisfiesConstructorPropertiesUntil20(const CXXConstructorDecl *Ctor,
+ ASTContext &Ctx) {
const CXXRecordDecl *Rec = Ctor->getParent();
llvm::SmallPtrSet<const RecordDecl *, 8> Bases{};
- for (const CXXBaseSpecifier Base : Rec->bases()) {
+ for (const CXXBaseSpecifier Base : Rec->bases())
Bases.insert(Base.getType()->getAsRecordDecl());
- }
+
llvm::SmallPtrSet<const FieldDecl *, 8> Fields{Rec->field_begin(),
Rec->field_end()};
llvm::SmallPtrSet<const FieldDecl *, 4> Indirects{};
@@ -147,7 +149,7 @@ bool satisfiesConstructorPropertiesUntil20(const CXXConstructorDecl *Ctor,
return true;
}
-const Type *unwrapPointee(const Type *T) {
+static const Type *unwrapPointee(const Type *T) {
if (!T->isPointerOrReferenceType())
return T;
@@ -163,11 +165,11 @@ const Type *unwrapPointee(const Type *T) {
return T;
}
-bool isLiteralType(QualType QT, const ASTContext &Ctx,
- const bool ConservativeLiteralType);
+static bool isLiteralType(QualType QT, const ASTContext &Ctx,
+ const bool ConservativeLiteralType);
-bool isLiteralType(const Type *T, const ASTContext &Ctx,
- const bool ConservativeLiteralType) {
+static bool isLiteralType(const Type *T, const ASTContext &Ctx,
+ const bool ConservativeLiteralType) {
if (!T)
return false;
@@ -211,18 +213,18 @@ bool isLiteralType(const Type *T, const ASTContext &Ctx,
return false;
}
-bool isLiteralType(QualType QT, const ASTContext &Ctx,
- const bool ConservativeLiteralType) {
+static bool isLiteralType(QualType QT, const ASTContext &Ctx,
+ const bool ConservativeLiteralType) {
return isLiteralType(QT.getTypePtr(), Ctx, ConservativeLiteralType);
}
-bool satisfiesProperties11(
+static bool satisfiesProperties11(
const FunctionDecl *FDecl, ASTContext &Ctx,
const bool ConservativeLiteralType,
const bool AddConstexprToMethodOfClassWithoutConstexprConstructor) {
- if (FDecl->isConstexprSpecified()) {
+ if (FDecl->isConstexprSpecified())
return true;
- }
+
const LangOptions LO = Ctx.getLangOpts();
const CXXMethodDecl *Method = llvm::dyn_cast<CXXMethodDecl>(FDecl);
if (Method && !Method->isStatic() &&
@@ -373,7 +375,7 @@ bool satisfiesProperties11(
// The only difference between C++14 and C++17 is that `constexpr` lambdas
// can be used in C++17.
-bool satisfiesProperties1417(
+static bool satisfiesProperties1417(
const FunctionDecl *FDecl, ASTContext &Ctx,
const bool ConservativeLiteralType,
const bool AddConstexprToMethodOfClassWithoutConstexprConstructor) {
@@ -573,13 +575,13 @@ bool satisfiesProperties1417(
return true;
}
-bool satisfiesProperties20(
+static bool satisfiesProperties20(
const FunctionDecl *FDecl, ASTContext &Ctx,
const bool ConservativeLiteralType,
const bool AddConstexprToMethodOfClassWithoutConstexprConstructor) {
- if (FDecl->isConstexprSpecified()) {
+ if (FDecl->isConstexprSpecified())
return true;
- }
+
const LangOptions LO = Ctx.getLangOpts();
const CXXMethodDecl *Method = llvm::dyn_cast<CXXMethodDecl>(FDecl);
if (Method && !Method->isStatic() &&
@@ -732,12 +734,12 @@ bool satisfiesProperties20(
return true;
}
-bool satisfiesProperties2326(
+static bool satisfiesProperties2326(
const FunctionDecl *FDecl, ASTContext &Ctx,
const bool AddConstexprToMethodOfClassWithoutConstexprConstructor) {
- if (FDecl->isConstexprSpecified()) {
+ if (FDecl->isConstexprSpecified())
return true;
- }
+
const LangOptions LO = Ctx.getLangOpts();
const CXXMethodDecl *Method = llvm::dyn_cast<CXXMethodDecl>(FDecl);
if (Method && !Method->isStatic() &&
@@ -757,8 +759,7 @@ bool satisfiesProperties2326(
return true;
}
-// FIXME: add test for uncalled lambda that throws, and called lambda that
-// throws
+namespace {
// FIXME: fix CXX23 allowing decomposition decls, but it is only a feature since
// CXX26
AST_MATCHER_P2(FunctionDecl, satisfiesProperties, bool, ConservativeLiteralType,
@@ -943,4 +944,4 @@ void UseConstexprCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "AddConstexprToMethodOfClassWithoutConstexprConstructor",
AddConstexprToMethodOfClassWithoutConstexprConstructor);
}
-} // namespace clang::tidy::misc
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.h b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
similarity index 78%
rename from clang-tools-extra/clang-tidy/misc/UseConstexprCheck.h
rename to clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
index 9a193e9f56518..0f4ae49962788 100644
--- a/clang-tools-extra/clang-tidy/misc/UseConstexprCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
@@ -6,20 +6,20 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USECONSTEXPRCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USECONSTEXPRCHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USECONSTEXPRCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USECONSTEXPRCHECK_H
#include "../ClangTidyCheck.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
-namespace clang::tidy::misc {
+namespace clang::tidy::modernize {
/// Find functions and variables that can be declared 'constexpr'.
///
/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/misc/use-constexpr.html
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-constexpr.html
class UseConstexprCheck : public ClangTidyCheck {
public:
UseConstexprCheck(StringRef Name, ClangTidyContext *Context);
@@ -38,6 +38,6 @@ class UseConstexprCheck : public ClangTidyCheck {
llvm::DenseMap<const VarDecl *, const FunctionDecl *> VariableMapping;
};
-} // namespace clang::tidy::misc
+} // namespace clang::tidy::modernize
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_USECONSTEXPRCHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USECONSTEXPRCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 8c331e0b0a403..3221df8ed6f0f 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -270,6 +270,10 @@ Changes in existing checks
excluding variables with ``thread_local`` storage class specifier from being
matched.
+- Added :doc:`modernize-use-constexpr
+ <clang-tidy/checks/modernize/use-constexpr>` check that finds functions and
+ variables that can be declared `constexpr`.
+
- Improved :doc:`modernize-use-default-member-init
<clang-tidy/checks/modernize/use-default-member-init>` check by matching
arithmetic operations, ``constexpr`` and ``static`` values, and detecting
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 9e6f99e01b7b0..d5c7b055b506b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -277,7 +277,6 @@ Clang-Tidy Checks
:doc:`misc-unused-parameters <misc/unused-parameters>`, "Yes"
:doc:`misc-unused-using-decls <misc/unused-using-decls>`, "Yes"
:doc:`misc-use-anonymous-namespace <misc/use-anonymous-namespace>`,
- :doc:`misc-use-constexpr <misc/use-constexpr>`, "Yes"
:doc:`misc-use-internal-linkage <misc/use-internal-linkage>`, "Yes"
:doc:`modernize-avoid-bind <modernize/avoid-bind>`, "Yes"
:doc:`modernize-avoid-c-arrays <modernize/avoid-c-arrays>`,
@@ -301,6 +300,7 @@ Clang-Tidy Checks
:doc:`modernize-unary-static-assert <modernize/unary-static-assert>`, "Yes"
:doc:`modernize-use-auto <modernize/use-auto>`, "Yes"
:doc:`modernize-use-bool-literals <modernize/use-bool-literals>`, "Yes"
+ :doc:`modernize-use-constexpr <modernize/use-constexpr>`, "Yes"
:doc:`modernize-use-constraints <modernize/use-constraints>`, "Yes"
:doc:`modernize-use-default-member-init <modernize/use-default-member-init>`, "Yes"
:doc:`modernize-use-designated-initializers <modernize/use-designated-initializers>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/use-constexpr.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
similarity index 92%
rename from clang-tools-extra/docs/clang-tidy/checks/misc/use-constexpr.rst
rename to clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
index 8205ab0e014d6..8a4def8098ac6 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/misc/use-constexpr.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - misc-use-constexpr
+.. title:: clang-tidy - modernize-use-constexpr
-misc-use-constexpr
-==================
+modernize-use-constexpr
+=======================
Find functions and variables that can be declared 'constexpr'.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr-cxx20.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-cxx20.cpp
similarity index 92%
rename from clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr-cxx20.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-cxx20.cpp
index bae1b87505bbc..dd400fe5185fc 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr-cxx20.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-cxx20.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++20 %s misc-use-constexpr %t
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-constexpr %t
namespace std {
template <typename T = void>
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
similarity index 78%
rename from clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
index 02496be16a007..7ac31d716812d 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/use-constexpr.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
@@ -1,21 +1,21 @@
-// RUN: %check_clang_tidy -std=c++11 -check-suffix=11 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++14 -check-suffix=11,14 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++17 -check-suffix=11,14,17 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++20 -check-suffix=11,14,17,20 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=11,14,17,20,23 %s misc-use-constexpr %t -- -- -fno-delayed-template-parsing
-
-// RUN: %check_clang_tidy -std=c++11 -check-suffix=11,11-CLT %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++14 -check-suffix=11,11-CLT,14,14-CLT %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++17 -check-suffix=11,11-CLT,14,14-CLT,17,17-CLT %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++20 -check-suffix=11,11-CLT,14,14-CLT,17,17-CLT,20,20-CLT %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
-// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=11,14,17,20,23 %s misc-use-constexpr %t -- -config="{CheckOptions: {misc-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++11 -check-suffix=11 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++14 -check-suffix=11,14 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++17 -check-suffix=11,14,17 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++20 -check-suffix=11,14,17,20 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=11,14,17,20,23 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+
+// RUN: %check_clang_tidy -std=c++11 -check-suffix=11,11-CLT %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++14 -check-suffix=11,11-CLT,14,14-CLT %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++17 -check-suffix=11,11-CLT,14,14-CLT,17,17-CLT %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++20 -check-suffix=11,11-CLT,14,14-CLT,17,17-CLT,20,20-CLT %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=11,14,17,20,23 %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConservativeLiteralType: false}}" -- -fno-delayed-template-parsing
namespace {
namespace my {
struct point {
constexpr point() {}
int get_x() const { return x; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:9: warning: function 'get_x' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:9: warning: function 'get_x' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr int get_x() const { return x; }
int x;
int y;
@@ -41,92 +41,92 @@ namespace function {
};
static void f1() {}
- // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static void f1() {}
static int f2() { return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f2() { return 0; }
static int f3(int x) { return x; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f3(int x) { return x; }
static int f4(Empty x) { return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f4(Empty x) { return 0; }
static int f5(Empty x) { return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f5(Empty x) { return 0; }
static int f6(Empty x) { ; return 0; }
- // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-14: constexpr static int f6(Empty x) { ; return 0; }
static int f7(Empty x) { static_assert(0 == 0, ""); return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f7(Empty x) { static_assert(0 == 0, ""); return 0; }
static int f8(Empty x) { using my_int = int; return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f8(Empty x) { using my_int = int; return 0; }
static int f9(Empty x) { using my::point; return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f9(Empty x) { using my::point; return 0; }
static int f10(Empty x) { return 10; return 0; }
- // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-14: constexpr static int f10(Empty x) { return 10; return 0; }
static int f11(Empty x) { if (true) return 10; return 0; }
- // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-14: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-14: constexpr static int f11(Empty x) { if (true) return 10; return 0; }
static int f12(Empty x) { label: ; goto label; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f12(Empty x) { label: ; goto label; return 0; }
static int f13(Empty x) { try { throw 0; } catch(int) {}; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f13(Empty x) { try { throw 0; } catch(int) {}; return 0; }
static int f14(Empty x) { asm ("mov %rax, %rax"); }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f14(Empty x) { asm ("mov %rax, %rax"); }
static int f15(Empty x) { int y; return 0; }
- // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-20: constexpr static int f15(Empty x) { int y; return 0; }
static int f16(Empty x) { static int y = 0; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f16(Empty x) { static int y = 0; return 0; }
static int f17(Empty x) { thread_local int y = 0; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f17(Empty x) { thread_local int y = 0; return 0; }
static int f18(Empty x) { [](){ label: ; goto label; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f18(Empty x) { [](){ label: ; goto label; return 0; }; return 0; }
static int f19(Empty x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f19(Empty x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
static int f20(Empty x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f20(Empty x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
static int f21(Empty x) { [](){ int y; return 0; }; return 0; }
- // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-20: constexpr static int f21(Empty x) { [](){ int y; return 0; }; return 0; }
static int f22(Empty x) { [](){ static int y = 0; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f22(Empty x) { [](){ static int y = 0; return 0; }; return 0; }
static int f23(Empty x) { [](){ thread_local int y = 0; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f23(Empty x) { [](){ thread_local int y = 0; return 0; }; return 0; }
static int f24(Empty x) { return [](){ return 0; }(); }
- // CHECK-MESSAGES-17: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-17: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-17: constexpr static int f24(Empty x) { return [](){ return 0; }(); }
static int f25(Empty x) { new int; return 0; }
- // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-20: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-20: constexpr static int f25(Empty x) { new int; return 0; }
struct Range0To10 {
@@ -140,9 +140,9 @@ namespace function {
iterator end() const;
};
static int f26(Empty x) {
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f26' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f26(Empty x) {
- // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f26' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-14-CLT: constexpr static int f26(Empty x) {
auto R = Range0To10{};
for (const int i: R) { }
@@ -165,92 +165,92 @@ namespace function_non_literal {
};
static void f1() {}
- // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static void f1() {}
static int f2() { return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f2() { return 0; }
static int f3(int x) { return x; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f3(int x) { return x; }
static int f4(NonLiteral x) { return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f4(NonLiteral x) { return 0; }
static int f5(NonLiteral x) { return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f5(NonLiteral x) { return 0; }
static int f6(NonLiteral x) { ; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f6(NonLiteral x) { ; return 0; }
static int f7(NonLiteral x) { static_assert(0 == 0, ""); return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f7(NonLiteral x) { static_assert(0 == 0, ""); return 0; }
static int f8(NonLiteral x) { using my_int = int; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f8(NonLiteral x) { using my_int = int; return 0; }
static int f9(NonLiteral x) { using my::point; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f9(NonLiteral x) { using my::point; return 0; }
static int f10(NonLiteral x) { return 10; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f10(NonLiteral x) { return 10; return 0; }
static int f11(NonLiteral x) { if (true) return 10; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f11(NonLiteral x) { if (true) return 10; return 0; }
static int f12(NonLiteral x) { label: ; goto label; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f12(NonLiteral x) { label: ; goto label; return 0; }
static int f13(NonLiteral x) { try { throw 0; } catch(int) {}; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f13(NonLiteral x) { try { throw 0; } catch(int) {}; return 0; }
static int f14(NonLiteral x) { asm ("mov %rax, %rax"); }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f14(NonLiteral x) { asm ("mov %rax, %rax"); }
static int f15(NonLiteral x) { int y; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f15(NonLiteral x) { int y; return 0; }
static int f16(NonLiteral x) { static int y = 0; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f16(NonLiteral x) { static int y = 0; return 0; }
static int f17(NonLiteral x) { thread_local int y = 0; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f17(NonLiteral x) { thread_local int y = 0; return 0; }
static int f18(NonLiteral x) { [](){ label: ; goto label; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f18(NonLiteral x) { [](){ label: ; goto label; return 0; }; return 0; }
static int f19(NonLiteral x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f19(NonLiteral x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
static int f20(NonLiteral x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f20(NonLiteral x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
static int f21(NonLiteral x) { [](){ int y; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f21(NonLiteral x) { [](){ int y; return 0; }; return 0; }
static int f22(NonLiteral x) { [](){ static int y = 0; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f22(NonLiteral x) { [](){ static int y = 0; return 0; }; return 0; }
static int f23(NonLiteral x) { [](){ thread_local int y = 0; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f23(NonLiteral x) { [](){ thread_local int y = 0; return 0; }; return 0; }
static int f24(NonLiteral x) { return [](){ return 0; }(); }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f24(NonLiteral x) { return [](){ return 0; }(); }
static int f25(NonLiteral x) { new int; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f25(NonLiteral x) { new int; return 0; }
struct Range0To10 {
@@ -268,7 +268,7 @@ namespace function_non_literal {
for (const int i: R) { }
return 0;
}
- // CHECK-MESSAGES-23: :[[@LINE-5]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-5]]:14: warning: function 'f26' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f26(NonLiteral x) {
} // namespace function_non_literal
namespace function_non_literal_ref {
@@ -287,116 +287,116 @@ namespace function_non_literal_ref {
};
static void f1() {}
- // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:15: warning: function 'f1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static void f1() {}
static int f2() { return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f2' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f2() { return 0; }
static int f3(int x) { return x; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:14: warning: function 'f3' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int f3(int x) { return x; }
static int f4(NonLiteral& x) { return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f4' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f4(NonLiteral& x) { return 0; }
- // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f4' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11-CLT: constexpr static int f4(NonLiteral& x) { return 0; }
static int f5(NonLiteral& x) { return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f5(NonLiteral& x) { return 0; }
- // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11-CLT: constexpr static int f5(NonLiteral& x) { return 0; }
static int f6(NonLiteral& x) { ; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f6' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f6(NonLiteral& x) { ; return 0; }
- // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f6' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f6' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-14-CLT: constexpr static int f6(NonLiteral& x) { ; return 0; }
static int f7(NonLiteral& x) { static_assert(0 == 0, ""); return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f7' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f7(NonLiteral& x) { static_assert(0 == 0, ""); return 0; }
- // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f7' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f7' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11-CLT: constexpr static int f7(NonLiteral& x) { static_assert(0 == 0, ""); return 0; }
static int f8(NonLiteral& x) { using my_int = int; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f8' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f8(NonLiteral& x) { using my_int = int; return 0; }
- // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f8' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f8' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11-CLT: constexpr static int f8(NonLiteral& x) { using my_int = int; return 0; }
static int f9(NonLiteral& x) { using my::point; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f9' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f9(NonLiteral& x) { using my::point; return 0; }
- // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f9' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11-CLT: :[[@LINE-3]]:14: warning: function 'f9' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11-CLT: constexpr static int f9(NonLiteral& x) { using my::point; return 0; }
static int f10(NonLiteral& x) { return 10; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f10' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f10(NonLiteral& x) { return 10; return 0; }
- // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f10' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f10' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-14-CLT: constexpr static int f10(NonLiteral& x) { return 10; return 0; }
static int f11(NonLiteral& x) { if (true) return 10; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f11' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f11(NonLiteral& x) { if (true) return 10; return 0; }
- // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f11' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-3]]:14: warning: function 'f11' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-14-CLT: constexpr static int f11(NonLiteral& x) { if (true) return 10; return 0; }
static int f12(NonLiteral& x) { label: ; goto label; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f12' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f12(NonLiteral& x) { label: ; goto label; return 0; }
static int f13(NonLiteral& x) { try { throw 0; } catch(int) {}; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f13' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f13(NonLiteral& x) { try { throw 0; } catch(int) {}; return 0; }
static int f14(NonLiteral& x) { asm ("mov %rax, %rax"); }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f14' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f14(NonLiteral& x) { asm ("mov %rax, %rax"); }
static int f15(NonLiteral& x) { int y; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f15' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f15(NonLiteral& x) { int y; return 0; }
- // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f15' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f15' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-20-CLT: constexpr static int f15(NonLiteral& x) { int y; return 0; }
static int f16(NonLiteral& x) { static int y = 0; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f16' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f16(NonLiteral& x) { static int y = 0; return 0; }
static int f17(NonLiteral& x) { thread_local int y = 0; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f17' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f17(NonLiteral& x) { thread_local int y = 0; return 0; }
static int f18(NonLiteral& x) { [](){ label: ; goto label; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f18' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f18(NonLiteral& x) { [](){ label: ; goto label; return 0; }; return 0; }
static int f19(NonLiteral& x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f19' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f19(NonLiteral& x) { [](){ try { throw 0; } catch(int) {}; return 0; }; return 0; }
static int f20(NonLiteral& x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f20' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f20(NonLiteral& x) { [](){ asm ("mov %rax, %rax"); }; return 0; }
static int f21(NonLiteral& x) { [](){ int y; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f21' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f21(NonLiteral& x) { [](){ int y; return 0; }; return 0; }
- // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f21' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f21' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-20-CLT: constexpr static int f21(NonLiteral& x) { [](){ int y; return 0; }; return 0; }
static int f22(NonLiteral& x) { [](){ static int y = 0; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f22' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f22(NonLiteral& x) { [](){ static int y = 0; return 0; }; return 0; }
static int f23(NonLiteral& x) { [](){ thread_local int y = 0; return 0; }; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f23' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f23(NonLiteral& x) { [](){ thread_local int y = 0; return 0; }; return 0; }
static int f24(NonLiteral& x) { return [](){ return 0; }(); }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f24' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f24(NonLiteral& x) { return [](){ return 0; }(); }
- // CHECK-MESSAGES-17-CLT: :[[@LINE-3]]:14: warning: function 'f24' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-17-CLT: :[[@LINE-3]]:14: warning: function 'f24' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-17-CLT: constexpr static int f24(NonLiteral& x) { return [](){ return 0; }(); }
static int f25(NonLiteral& x) { new int; return 0; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'f25' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f25(NonLiteral& x) { new int; return 0; }
- // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f25' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-20-CLT: :[[@LINE-3]]:14: warning: function 'f25' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-20-CLT: constexpr static int f25(NonLiteral& x) { new int; return 0; }
struct Range0To10 {
@@ -414,9 +414,9 @@ namespace function_non_literal_ref {
for (const int i: R) { }
return 0;
}
- // CHECK-MESSAGES-23: :[[@LINE-5]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-5]]:14: warning: function 'f26' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr static int f26(NonLiteral& x) {
- // CHECK-MESSAGES-14-CLT: :[[@LINE-7]]:14: warning: function 'f26' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-14-CLT: :[[@LINE-7]]:14: warning: function 'f26' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-14-CLT: constexpr static int f26(NonLiteral& x) {
} // namespace function_non_literal_ref
@@ -425,29 +425,29 @@ namespace variable {
namespace literal_type {
constexpr int f1() { return 0; }
int g1() { return 0; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:13: warning: function 'g1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:13: warning: function 'g1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr int g1() { return 0; }
static constexpr int A1 = 0;
static int B1 = 0;
static const int C1 = 0;
- // CHECK-MESSAGES-11: :[[@LINE-1]]:26: warning: variable 'C1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:26: warning: variable 'C1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int C1 = 0;
static const int D1 = f1();
- // CHECK-MESSAGES-11: :[[@LINE-1]]:26: warning: variable 'D1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:26: warning: variable 'D1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static int D1 = f1();
static const int E1 = g1();
template <typename T>
const T TemplatedVar1 = T{};
- // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: variable 'TemplatedVar1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: variable 'TemplatedVar1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr T TemplatedVar1 = T{};
void h1() {
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr void h1() {
int a1 = 0;
const int b1 = 1;
- // CHECK-MESSAGES-11: :[[@LINE-1]]:23: warning: variable 'b1' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:23: warning: variable 'b1' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr int b1 = 1;
static int c1 = 2;
static const int d1 = 3;
@@ -460,23 +460,23 @@ namespace variable {
struct AStruct { int val; };
constexpr AStruct f2() { return {}; }
AStruct g2() { return {}; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: function 'g2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: function 'g2' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr AStruct g2() { return {}; }
static constexpr AStruct A2 = {};
static AStruct B2 = {};
static const AStruct C2 = {};
- // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'C2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'C2' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static AStruct C2 = {};
static const AStruct D2 = f2();
- // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'D2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'D2' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static AStruct D2 = f2();
static const AStruct E2 = g2();
void h2() {
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h2' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr void h2() {
AStruct a2{};
const AStruct b2{};
- // CHECK-MESSAGES-11: :[[@LINE-1]]:27: warning: variable 'b2' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:27: warning: variable 'b2' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr AStruct b2{};
static AStruct c2{};
static const AStruct d2{};
@@ -486,7 +486,7 @@ namespace variable {
namespace struct_type_non_literal {
struct AStruct { ~AStruct(); int val; };
AStruct g3() { return {}; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:17: warning: function 'g3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:17: warning: function 'g3' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr AStruct g3() { return {}; }
static AStruct B3 = {};
static const AStruct C3 = {};
@@ -496,11 +496,11 @@ namespace variable {
const T TemplatedVar2 = T{};
template <typename T>
const T TemplatedVar2B = T{};
- // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: variable 'TemplatedVar2B' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: variable 'TemplatedVar2B' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr T TemplatedVar2B = T{};
void h3() {
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h3' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h3' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr void h3() {
AStruct a3{};
const AStruct b3{};
@@ -516,13 +516,13 @@ namespace variable {
namespace struct_type_non_literal2 {
struct AStruct { volatile int Val; };
AStruct g4() { return {}; }
- // CHECK-MESSAGES-23: :[[@LINE-1]]:17: warning: function 'g4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:17: warning: function 'g4' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr AStruct g4() { return {}; }
static AStruct B4 = {};
static const AStruct C4 = {};
static const AStruct E4 = g4();
void h4() {
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h4' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h4' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr void h4() {
AStruct a4{};
const AStruct b4{};
@@ -535,23 +535,23 @@ namespace variable {
struct AStruct { union { int val; float val5; }; };
constexpr AStruct f5() { return {}; }
AStruct g5() { return {}; }
- // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: function 'g5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:17: warning: function 'g5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr AStruct g5() { return {}; }
static constexpr AStruct A5 = {};
static AStruct B5 = {};
static const AStruct C5 = {};
- // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'C5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'C5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static AStruct C5 = {};
static const AStruct D5 = f5();
- // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'D5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:30: warning: variable 'D5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr static AStruct D5 = f5();
static const AStruct E5 = g5();
void h5() {
- // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:14: warning: function 'h5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-23: constexpr void h5() {
AStruct a5{};
const AStruct b5{};
- // CHECK-MESSAGES-11: :[[@LINE-1]]:27: warning: variable 'b5' can be declared 'constexpr' [misc-use-constexpr]
+ // CHECK-MESSAGES-11: :[[@LINE-1]]:27: warning: variable 'b5' can be declared 'constexpr' [modernize-use-constexpr]
// CHECK-FIXES-11: constexpr AStruct b5{};
static AStruct c5{};
static const AStruct d5{};
>From 12cf4eb01db19a5c4575a70ce64e50c995161eed Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Tue, 1 Jul 2025 18:47:18 +0200
Subject: [PATCH 03/11] fix formatting
---
clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 5afe0b0e1a69f..b33f2ccbd6c21 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -77,8 +77,7 @@ class ModernizeModule : public ClangTidyModule {
CheckFactories.registerCheck<MinMaxUseInitializerListCheck>(
"modernize-min-max-use-initializer-list");
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
- CheckFactories.registerCheck<UseConstexprCheck>(
- "modernize-use-constexpr");
+ CheckFactories.registerCheck<UseConstexprCheck>("modernize-use-constexpr");
CheckFactories.registerCheck<UseDesignatedInitializersCheck>(
"modernize-use-designated-initializers");
CheckFactories.registerCheck<UseIntegerSignComparisonCheck>(
>From 7a32e076bef1ef392e69ea39dbc8b9407481874c Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Tue, 1 Jul 2025 23:18:45 +0200
Subject: [PATCH 04/11] add ConstexprString option
---
.../clang-tidy/modernize/UseConstexprCheck.cpp | 9 ++++++---
.../clang-tidy/modernize/UseConstexprCheck.h | 1 +
.../docs/clang-tidy/checks/modernize/use-constexpr.rst | 5 +++++
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
index cbfdde4f61920..201cb19a84239 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
@@ -908,7 +908,7 @@ void UseConstexprCheck::onEndOfTranslationUnit() {
for (const Decl *D : Func->redecls())
if (const auto *FDecl = llvm::dyn_cast<FunctionDecl>(D))
Diag << FixItHint::CreateInsertion(FDecl->getInnerLocStart(),
- "constexpr ");
+ ConstexprString + " ");
}
for (const auto &[Var, FuncCtx] : VariableMapping) {
if (FuncCtx && getLangOpts().CPlusPlus23 && Var->isStaticLocal() &&
@@ -919,7 +919,8 @@ void UseConstexprCheck::onEndOfTranslationUnit() {
auto Diag =
diag(Var->getLocation(), "variable %0 can be declared 'constexpr'")
<< Var << R
- << FixItHint::CreateInsertion(Var->getInnerLocStart(), "constexpr ");
+ << FixItHint::CreateInsertion(Var->getInnerLocStart(),
+ ConstexprString + " ");
if (const std::optional<Token> ConstToken =
utils::lexer::getQualifyingToken(
tok::TokenKind::kw_const,
@@ -938,10 +939,12 @@ UseConstexprCheck::UseConstexprCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
ConservativeLiteralType(Options.get("ConservativeLiteralType", true)),
AddConstexprToMethodOfClassWithoutConstexprConstructor(Options.get(
- "AddConstexprToMethodOfClassWithoutConstexprConstructor", false)) {}
+ "AddConstexprToMethodOfClassWithoutConstexprConstructor", false)),
+ ConstexprString(Options.get("ConstexprString", "constexpr")) {}
void UseConstexprCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "ConservativeLiteralType", ConservativeLiteralType);
Options.store(Opts, "AddConstexprToMethodOfClassWithoutConstexprConstructor",
AddConstexprToMethodOfClassWithoutConstexprConstructor);
+ Options.store(Opts, "ConstexprString", ConstexprString);
}
} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
index 0f4ae49962788..c8030305d6f11 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
@@ -34,6 +34,7 @@ class UseConstexprCheck : public ClangTidyCheck {
private:
const bool ConservativeLiteralType;
const bool AddConstexprToMethodOfClassWithoutConstexprConstructor;
+ const std::string ConstexprString;
llvm::SmallPtrSet<const FunctionDecl *, 32> Functions;
llvm::DenseMap<const VarDecl *, const FunctionDecl *> VariableMapping;
};
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
index 8a4def8098ac6..949d2df47cc3d 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
@@ -38,3 +38,8 @@ Options
``constexpr`` to a member function is superfluous. This option controls if
``constexpr`` should be added anyways. Default is ``false``.
+.. option:: ConstexprString
+
+ The string to use to specify something as ``constexpr``, for example, a macro.
+ Default is ``constexpr``.
+
>From 11913fa0fb7afeeca01a0019b1436f4bfb3351b6 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Tue, 1 Jul 2025 23:19:57 +0200
Subject: [PATCH 05/11] align short explanation of check
---
clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h | 2 +-
.../docs/clang-tidy/checks/modernize/use-constexpr.rst | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
index c8030305d6f11..bd2ef5257bb5e 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
@@ -16,7 +16,7 @@
namespace clang::tidy::modernize {
-/// Find functions and variables that can be declared 'constexpr'.
+/// Finds functions and variables that can be declared 'constexpr'.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-constexpr.html
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
index 949d2df47cc3d..5ba39eee9c15b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
@@ -3,7 +3,7 @@
modernize-use-constexpr
=======================
-Find functions and variables that can be declared 'constexpr'.
+Finds functions and variables that can be declared 'constexpr'.
The check analyses any function and variable according to the rules defined
for the language version that the code is compiled with.
>From 3633dd506dd14a8c7ef108459ccf887afb40b5e3 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Tue, 1 Jul 2025 23:20:32 +0200
Subject: [PATCH 06/11] move release note entry to correct location
---
clang-tools-extra/docs/ReleaseNotes.rst | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3221df8ed6f0f..d91b558ff5393 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -142,6 +142,10 @@ New checks
Finds unscoped (non-class) ``enum`` declarations and suggests using
``enum class`` instead.
+- New :doc:`modernize-use-constexpr
+ <clang-tidy/checks/modernize/use-constexpr>` check that finds functions and
+ variables that can be declared `constexpr`.
+
- New :doc:`modernize-use-scoped-lock
<clang-tidy/checks/modernize/use-scoped-lock>` check.
@@ -270,10 +274,6 @@ Changes in existing checks
excluding variables with ``thread_local`` storage class specifier from being
matched.
-- Added :doc:`modernize-use-constexpr
- <clang-tidy/checks/modernize/use-constexpr>` check that finds functions and
- variables that can be declared `constexpr`.
-
- Improved :doc:`modernize-use-default-member-init
<clang-tidy/checks/modernize/use-default-member-init>` check by matching
arithmetic operations, ``constexpr`` and ``static`` values, and detecting
>From 28afda53f40e1f08592f6e8eda5b99ee80bafb7e Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Tue, 1 Jul 2025 23:22:59 +0200
Subject: [PATCH 07/11] fix removal range of `const` kw
---
.../clang-tidy/modernize/UseConstexprCheck.cpp | 11 ++++++++---
.../clang-tidy/checkers/modernize/use-constexpr.cpp | 4 ++++
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
index 201cb19a84239..5eaa46270d7fd 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
@@ -921,11 +921,16 @@ void UseConstexprCheck::onEndOfTranslationUnit() {
<< Var << R
<< FixItHint::CreateInsertion(Var->getInnerLocStart(),
ConstexprString + " ");
+ // Since either of the locs can be in a macro, use `makeFileCharRange` to be
+ // sure that we have a consistent `CharSourceRange`, located entirely in the
+ // source file.
+ CharSourceRange FileRange = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(Var->getInnerLocStart(),
+ Var->getLocation()),
+ Var->getASTContext().getSourceManager(), getLangOpts());
if (const std::optional<Token> ConstToken =
utils::lexer::getQualifyingToken(
- tok::TokenKind::kw_const,
- CharSourceRange::getTokenRange(Var->getSourceRange()),
- Var->getASTContext(),
+ tok::TokenKind::kw_const, FileRange, Var->getASTContext(),
Var->getASTContext().getSourceManager())) {
Diag << FixItHint::CreateRemoval(ConstToken->getLocation());
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
index 7ac31d716812d..83c89a41852b5 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
@@ -454,6 +454,10 @@ namespace variable {
static auto e1 = TemplatedVar1<int> + TemplatedVar1<unsigned int>;
}
+
+ const auto check = [](const int & ref) { };
+ // CHECK-MESSAGES-17: :[[@LINE-1]]:16: warning: variable 'check' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES-17: constexpr auto check = [](const int & ref) { };
} // namespace literal_type
namespace struct_type {
>From 7832be91b8d15a07b6b82007247e5328fde75814 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Tue, 1 Jul 2025 23:36:54 +0200
Subject: [PATCH 08/11] move replacement string creation out of loop
---
.../clang-tidy/modernize/UseConstexprCheck.cpp | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
index 5eaa46270d7fd..7eb2e74316c88 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
@@ -898,6 +898,7 @@ void UseConstexprCheck::check(const MatchFinder::MatchResult &Result) {
}
void UseConstexprCheck::onEndOfTranslationUnit() {
+ const std::string FunctionReplacement = ConstexprString + " ";
for (const FunctionDecl *Func : Functions) {
const SourceRange R =
SourceRange(Func->getInnerLocStart(), Func->getLocation());
@@ -908,8 +909,9 @@ void UseConstexprCheck::onEndOfTranslationUnit() {
for (const Decl *D : Func->redecls())
if (const auto *FDecl = llvm::dyn_cast<FunctionDecl>(D))
Diag << FixItHint::CreateInsertion(FDecl->getInnerLocStart(),
- ConstexprString + " ");
+ FunctionReplacement);
}
+ const std::string VariableReplacement = ConstexprString + " ";
for (const auto &[Var, FuncCtx] : VariableMapping) {
if (FuncCtx && getLangOpts().CPlusPlus23 && Var->isStaticLocal() &&
Functions.contains(FuncCtx))
@@ -920,11 +922,11 @@ void UseConstexprCheck::onEndOfTranslationUnit() {
diag(Var->getLocation(), "variable %0 can be declared 'constexpr'")
<< Var << R
<< FixItHint::CreateInsertion(Var->getInnerLocStart(),
- ConstexprString + " ");
+ VariableReplacement);
// Since either of the locs can be in a macro, use `makeFileCharRange` to be
// sure that we have a consistent `CharSourceRange`, located entirely in the
// source file.
- CharSourceRange FileRange = Lexer::makeFileCharRange(
+ const CharSourceRange FileRange = Lexer::makeFileCharRange(
CharSourceRange::getCharRange(Var->getInnerLocStart(),
Var->getLocation()),
Var->getASTContext().getSourceManager(), getLangOpts());
>From a97b851a3050a04e4ff4e6262a763617955951aa Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Wed, 2 Jul 2025 00:31:35 +0200
Subject: [PATCH 09/11] add StaticConstexprString option
---
.../modernize/UseConstexprCheck.cpp | 38 ++++++++++++++++---
.../clang-tidy/modernize/UseConstexprCheck.h | 1 +
.../modernize/use-constexpr-locals.cpp | 20 ++++++++++
.../use-constexpr-replacement-opts.cpp | 32 ++++++++++++++++
.../checkers/modernize/use-constexpr.cpp | 8 ++--
5 files changed, 90 insertions(+), 9 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-locals.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-replacement-opts.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
index 7eb2e74316c88..4f1d5e339d11e 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.cpp
@@ -911,18 +911,43 @@ void UseConstexprCheck::onEndOfTranslationUnit() {
Diag << FixItHint::CreateInsertion(FDecl->getInnerLocStart(),
FunctionReplacement);
}
- const std::string VariableReplacement = ConstexprString + " ";
+
+ const std::string VariableReplacementWithStatic = StaticConstexprString + " ";
+ const auto VariableReplacement =
+ [&FunctionReplacement, this, &VariableReplacementWithStatic](
+ const VarDecl *Var, const FunctionDecl *FuncCtx,
+ const bool IsAddingConstexprToFuncCtx) -> const std::string & {
+ if (!FuncCtx)
+ return FunctionReplacement;
+
+ if (!getLangOpts().CPlusPlus23)
+ return FunctionReplacement;
+
+ // We'll prefer the function to be constexpr over the function not being
+ // constexpr just for the var to be static constexpr instead of just
+ // constexpr.
+ if (IsAddingConstexprToFuncCtx)
+ return FunctionReplacement;
+
+ if (Var->isStaticLocal())
+ return FunctionReplacement;
+
+ return VariableReplacementWithStatic;
+ };
+
for (const auto &[Var, FuncCtx] : VariableMapping) {
+ const auto IsAddingConstexprToFuncCtx = Functions.contains(FuncCtx);
if (FuncCtx && getLangOpts().CPlusPlus23 && Var->isStaticLocal() &&
- Functions.contains(FuncCtx))
+ IsAddingConstexprToFuncCtx)
continue;
const SourceRange R =
SourceRange(Var->getInnerLocStart(), Var->getLocation());
auto Diag =
diag(Var->getLocation(), "variable %0 can be declared 'constexpr'")
<< Var << R
- << FixItHint::CreateInsertion(Var->getInnerLocStart(),
- VariableReplacement);
+ << FixItHint::CreateInsertion(
+ Var->getInnerLocStart(),
+ VariableReplacement(Var, FuncCtx, IsAddingConstexprToFuncCtx));
// Since either of the locs can be in a macro, use `makeFileCharRange` to be
// sure that we have a consistent `CharSourceRange`, located entirely in the
// source file.
@@ -947,11 +972,14 @@ UseConstexprCheck::UseConstexprCheck(StringRef Name, ClangTidyContext *Context)
ConservativeLiteralType(Options.get("ConservativeLiteralType", true)),
AddConstexprToMethodOfClassWithoutConstexprConstructor(Options.get(
"AddConstexprToMethodOfClassWithoutConstexprConstructor", false)),
- ConstexprString(Options.get("ConstexprString", "constexpr")) {}
+ ConstexprString(Options.get("ConstexprString", "constexpr")),
+ StaticConstexprString(
+ Options.get("StaticConstexprString", "static " + ConstexprString)) {}
void UseConstexprCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "ConservativeLiteralType", ConservativeLiteralType);
Options.store(Opts, "AddConstexprToMethodOfClassWithoutConstexprConstructor",
AddConstexprToMethodOfClassWithoutConstexprConstructor);
Options.store(Opts, "ConstexprString", ConstexprString);
+ Options.store(Opts, "StaticConstexprString", StaticConstexprString);
}
} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
index bd2ef5257bb5e..061ee8aa58a30 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseConstexprCheck.h
@@ -35,6 +35,7 @@ class UseConstexprCheck : public ClangTidyCheck {
const bool ConservativeLiteralType;
const bool AddConstexprToMethodOfClassWithoutConstexprConstructor;
const std::string ConstexprString;
+ const std::string StaticConstexprString;
llvm::SmallPtrSet<const FunctionDecl *, 32> Functions;
llvm::DenseMap<const VarDecl *, const FunctionDecl *> VariableMapping;
};
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-locals.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-locals.cpp
new file mode 100644
index 0000000000000..e4bcdc7b3dae5
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-locals.cpp
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy -std=c++11 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++14 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++17 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=23 %s modernize-use-constexpr %t -- -- -fno-delayed-template-parsing
+
+
+#define FUNC(N) void func##N()
+FUNC(0) {
+ static int f1 = 1;
+ static const int f2 = 2;
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:22: warning: variable 'f2' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES-23: constexpr static int f2 = 2;
+ const int f3 = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: variable 'f3' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES: constexpr int f3 = 3;
+ // CHECK-MESSAGES-23: :[[@LINE-3]]:15: warning: variable 'f3' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES-23: static constexpr int f3 = 3;
+}
+
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-replacement-opts.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-replacement-opts.cpp
new file mode 100644
index 0000000000000..39d3cb837f0d3
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr-replacement-opts.cpp
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy -std=c++11 %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConstexprString: 'CXPR'}}"
+// RUN: %check_clang_tidy -std=c++14 %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConstexprString: 'CXPR'}}"
+// RUN: %check_clang_tidy -std=c++17 %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConstexprString: 'CXPR'}}"
+// RUN: %check_clang_tidy -std=c++20 %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConstexprString: 'CXPR'}}"
+// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=23 %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConstexprString: 'CXPR'}}"
+// RUN: %check_clang_tidy -std=c++23-or-later -check-suffix=23-STATIC %s modernize-use-constexpr %t -- -config="{CheckOptions: {modernize-use-constexpr.ConstexprString: 'CXPR', modernize-use-constexpr.StaticConstexprString: 'STATIC_CXPR'}}"
+
+static int f1() { return 0; }
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: function 'f1' can be declared 'constexpr' [modernize-use-constexpr]
+// CHECK-FIXES: CXPR static int f1() { return 0; }
+// CHECK-MESSAGES-23: :[[@LINE-3]]:12: warning: function 'f1' can be declared 'constexpr' [modernize-use-constexpr]
+// CHECK-FIXES-23: CXPR static int f1() { return 0; }
+// CHECK-MESSAGES-23-STATIC: :[[@LINE-5]]:12: warning: function 'f1' can be declared 'constexpr' [modernize-use-constexpr]
+// CHECK-FIXES-23-STATIC: CXPR static int f1() { return 0; }
+
+#define FUNC(N) void func##N()
+FUNC(0) {
+ static int f1 = 1;
+ static const int f2 = 2;
+ // CHECK-MESSAGES-23: :[[@LINE-1]]:22: warning: variable 'f2' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES-23: CXPR static int f2 = 2;
+ // CHECK-MESSAGES-23-STATIC: :[[@LINE-3]]:22: warning: variable 'f2' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES-23-STATIC: CXPR static int f2 = 2;
+ const int f3 = 3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: variable 'f3' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES: CXPR int f3 = 3;
+ // CHECK-MESSAGES-23: :[[@LINE-3]]:15: warning: variable 'f3' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES-23: static CXPR int f3 = 3;
+ // CHECK-MESSAGES-23-STATIC: :[[@LINE-5]]:15: warning: variable 'f3' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES-23-STATIC: STATIC_CXPR int f3 = 3;
+}
+
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
index 83c89a41852b5..9fca53b08f35c 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constexpr.cpp
@@ -453,11 +453,11 @@ namespace variable {
static const int d1 = 3;
static auto e1 = TemplatedVar1<int> + TemplatedVar1<unsigned int>;
- }
- const auto check = [](const int & ref) { };
- // CHECK-MESSAGES-17: :[[@LINE-1]]:16: warning: variable 'check' can be declared 'constexpr' [modernize-use-constexpr]
- // CHECK-FIXES-17: constexpr auto check = [](const int & ref) { };
+ const auto check = [](const int & ref) { };
+ // CHECK-MESSAGES-17: :[[@LINE-1]]:24: warning: variable 'check' can be declared 'constexpr' [modernize-use-constexpr]
+ // CHECK-FIXES-17: constexpr auto check = [](const int & ref) { };
+ }
} // namespace literal_type
namespace struct_type {
>From 85a3a5031dd5dc7600a6c5cc228ae239ad59227c Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Wed, 2 Jul 2025 00:49:25 +0200
Subject: [PATCH 10/11] explain `const` dependency in docs + small docs fixes
---
.../checks/modernize/use-constexpr.rst | 29 +++++++++++++++----
1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
index 5ba39eee9c15b..bc608e67360f4 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
@@ -9,6 +9,19 @@ The check analyses any function and variable according to the rules defined
for the language version that the code is compiled with.
Changing to a newer language standard may therefore offer additional opportunity
to declare a function or variable as ``constexpr``.
+Furthermore, this check can be incremental in terms of its diagnostics. For
+example, declaring a function ``constepxr`` might create new opportunities of
+marking additional variables or function ``constexpr``, which can only be found
+in subsequent runs of this check.
+
+For variables, the check will only detect variables that can be declared
+``constexpr`` if they are already ``const``.
+This is because this check would have to duplicate the expensive analysis of the
+:doc:`misc-const-correctness<clang-tidy/checks/misc/const-correctness>` check.
+Therefore, it is recommended to have
+:doc:`misc-const-correctness<clang-tidy/checks/misc/const-correctness>` enabled
+in the Clang-Tidy config when this check is, so that all opportunities for
+``const`` and also ``constexpr`` are explored.
Options
-------
@@ -26,9 +39,9 @@ Options
int &ref;
};
- This type is a literal type, but can not be constructed at compile-time,
- so with `ConservativeLiteralType` equal to `true`, variables or funtions
- with this type are not considered to support ``constexpr``. Default is
+ This type is a literal type, but can not be constructed at compile-time.
+ With `ConservativeLiteralType` equal to `true`, variables or funtions
+ with this type are not diagnosed to add ``constexpr``. Default is
`true`.
.. option:: AddConstexprToMethodOfClassWithoutConstexprConstructor
@@ -40,6 +53,12 @@ Options
.. option:: ConstexprString
- The string to use to specify something as ``constexpr``, for example, a macro.
- Default is ``constexpr``.
+ The string to use to specify a variable or function as ``constexpr``, for
+ example, a macro. Default is ``constexpr``.
+
+.. option:: ConstexprString
+
+ The string to use with C++23 to specify a function-local variable as ``static
+ constexpr``, for example, a macro. Default is ``static constexpr``
+ (concatenating ``static `` with the `ConstexprString` option).
>From a78c181970b209ceea80d71e1f9617a23195d458 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <git.julian.schmidt at gmail.com>
Date: Wed, 2 Jul 2025 00:53:17 +0200
Subject: [PATCH 11/11] fix doc inline code line break
---
.../docs/clang-tidy/checks/modernize/use-constexpr.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
index bc608e67360f4..a97bab2734ee8 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constexpr.rst
@@ -58,7 +58,7 @@ Options
.. option:: ConstexprString
- The string to use with C++23 to specify a function-local variable as ``static
- constexpr``, for example, a macro. Default is ``static constexpr``
+ The string to use with C++23 to specify a function-local variable as
+ ``static constexpr``, for example, a macro. Default is ``static constexpr``
(concatenating ``static `` with the `ConstexprString` option).
More information about the cfe-commits
mailing list