11#include "clang/AST/Expr.h"
18 const auto CacheEntry = FunctionCache.find(
FuncDecl);
19 if (CacheEntry == FunctionCache.end()) {
27 return CacheEntry->getSecond();
31ExceptionSpecAnalyzer::analyzeUnresolvedOrDefaulted(
32 const CXXMethodDecl *MethodDecl,
const FunctionProtoType *FuncProto) {
33 if (!FuncProto || !MethodDecl)
36 const DefaultableMemberKind
Kind = getDefaultableMemberKind(MethodDecl);
38 if (
Kind == DefaultableMemberKind::None)
41 return analyzeRecord(MethodDecl->getParent(),
Kind, SkipMethods::Yes);
45ExceptionSpecAnalyzer::analyzeFieldDecl(
const FieldDecl *FDecl,
46 DefaultableMemberKind
Kind) {
50 if (
const CXXRecordDecl *RecDecl =
51 FDecl->getType()->getUnqualifiedDesugaredType()->getAsCXXRecordDecl())
52 return analyzeRecord(RecDecl,
Kind);
55 if (FDecl->getType().isTrivialType(FDecl->getASTContext()))
62ExceptionSpecAnalyzer::analyzeBase(
const CXXBaseSpecifier &Base,
63 DefaultableMemberKind
Kind) {
64 const auto *RecType = Base.getType()->getAs<RecordType>();
68 const auto *BaseClass = cast<CXXRecordDecl>(RecType->getDecl());
70 return analyzeRecord(BaseClass,
Kind);
74ExceptionSpecAnalyzer::analyzeRecord(
const CXXRecordDecl *RecordDecl,
75 DefaultableMemberKind
Kind,
76 SkipMethods SkipMethods) {
81 if (hasTrivialMemberKind(RecordDecl,
Kind))
84 if (SkipMethods == SkipMethods::No)
85 for (
const auto *MethodDecl : RecordDecl->methods())
86 if (getDefaultableMemberKind(MethodDecl) ==
Kind)
89 for (
const auto &BaseSpec : RecordDecl->bases()) {
90 State Result = analyzeBase(BaseSpec,
Kind);
95 for (
const auto &BaseSpec : RecordDecl->vbases()) {
96 State Result = analyzeBase(BaseSpec,
Kind);
101 for (
const auto *FDecl : RecordDecl->fields())
102 if (!FDecl->isInvalidDecl() && !FDecl->isUnnamedBitField()) {
103 State Result = analyzeFieldDecl(FDecl,
Kind);
112ExceptionSpecAnalyzer::analyzeImpl(
const FunctionDecl *
FuncDecl) {
113 const auto *FuncProto =
FuncDecl->getType()->getAs<FunctionProtoType>();
117 const ExceptionSpecificationType EST = FuncProto->getExceptionSpecType();
119 if (EST == EST_Unevaluated || (EST == EST_None &&
FuncDecl->isDefaulted()))
120 return analyzeUnresolvedOrDefaulted(cast<CXXMethodDecl>(
FuncDecl),
123 return analyzeFunctionEST(
FuncDecl, FuncProto);
127ExceptionSpecAnalyzer::analyzeFunctionEST(
const FunctionDecl *
FuncDecl,
128 const FunctionProtoType *FuncProto) {
132 if (isUnresolvedExceptionSpec(FuncProto->getExceptionSpecType()))
136 if (isa<CXXDestructorDecl>(
FuncDecl) &&
137 FuncDecl->getExceptionSpecType() == EST_None)
140 switch (FuncProto->canThrow()) {
144 const Expr *NoexceptExpr = FuncProto->getNoexceptExpr();
149 if (NoexceptExpr->isValueDependent())
154 if (NoexceptExpr->EvaluateAsBooleanCondition(
155 Result,
FuncDecl->getASTContext(),
true))
167bool ExceptionSpecAnalyzer::hasTrivialMemberKind(
const CXXRecordDecl *RecDecl,
168 DefaultableMemberKind
Kind) {
173 case DefaultableMemberKind::DefaultConstructor:
174 return RecDecl->hasTrivialDefaultConstructor();
175 case DefaultableMemberKind::CopyConstructor:
176 return RecDecl->hasTrivialCopyConstructor();
177 case DefaultableMemberKind::MoveConstructor:
178 return RecDecl->hasTrivialMoveConstructor();
179 case DefaultableMemberKind::CopyAssignment:
180 return RecDecl->hasTrivialCopyAssignment();
181 case DefaultableMemberKind::MoveAssignment:
182 return RecDecl->hasTrivialMoveAssignment();
183 case DefaultableMemberKind::Destructor:
184 return RecDecl->hasTrivialDestructor();
191bool ExceptionSpecAnalyzer::isConstructor(DefaultableMemberKind
Kind) {
193 case DefaultableMemberKind::DefaultConstructor:
194 case DefaultableMemberKind::CopyConstructor:
195 case DefaultableMemberKind::MoveConstructor:
203bool ExceptionSpecAnalyzer::isSpecialMember(DefaultableMemberKind
Kind) {
205 case DefaultableMemberKind::DefaultConstructor:
206 case DefaultableMemberKind::CopyConstructor:
207 case DefaultableMemberKind::MoveConstructor:
208 case DefaultableMemberKind::CopyAssignment:
209 case DefaultableMemberKind::MoveAssignment:
210 case DefaultableMemberKind::Destructor:
217bool ExceptionSpecAnalyzer::isComparison(DefaultableMemberKind
Kind) {
219 case DefaultableMemberKind::CompareEqual:
220 case DefaultableMemberKind::CompareNotEqual:
221 case DefaultableMemberKind::CompareRelational:
222 case DefaultableMemberKind::CompareThreeWay:
229ExceptionSpecAnalyzer::DefaultableMemberKind
230ExceptionSpecAnalyzer::getDefaultableMemberKind(
const FunctionDecl *
FuncDecl) {
231 if (
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(
FuncDecl)) {
232 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(
FuncDecl)) {
233 if (Ctor->isDefaultConstructor())
234 return DefaultableMemberKind::DefaultConstructor;
236 if (Ctor->isCopyConstructor())
237 return DefaultableMemberKind::CopyConstructor;
239 if (Ctor->isMoveConstructor())
240 return DefaultableMemberKind::MoveConstructor;
243 if (MethodDecl->isCopyAssignmentOperator())
244 return DefaultableMemberKind::CopyAssignment;
246 if (MethodDecl->isMoveAssignmentOperator())
247 return DefaultableMemberKind::MoveAssignment;
249 if (isa<CXXDestructorDecl>(
FuncDecl))
250 return DefaultableMemberKind::Destructor;
253 const LangOptions &LangOpts =
FuncDecl->getLangOpts();
255 switch (
FuncDecl->getDeclName().getCXXOverloadedOperator()) {
257 return DefaultableMemberKind::CompareEqual;
259 case OO_ExclaimEqual:
260 return DefaultableMemberKind::CompareNotEqual;
264 if (!LangOpts.CPlusPlus20)
266 return DefaultableMemberKind::CompareThreeWay;
271 case OO_GreaterEqual:
273 if (!LangOpts.CPlusPlus20)
275 return DefaultableMemberKind::CompareRelational;
282 return DefaultableMemberKind::None;
State analyze(const FunctionDecl *FuncDecl)
@ Throwing
This function has been declared as possibly throwing.
@ Unknown
We're unable to tell if this function is declared as throwing or not.
@ NotThrowing
This function has been declared as not throwing.
static constexpr const char FuncDecl[]