11#include "clang/AST/Expr.h"
12#include "clang/AST/Type.h"
20 const auto [CacheEntry, NotFound] =
29 return CacheEntry->getSecond();
33ExceptionSpecAnalyzer::analyzeUnresolvedOrDefaulted(
34 const CXXMethodDecl *MethodDecl,
const FunctionProtoType *FuncProto) {
35 if (!FuncProto || !MethodDecl)
38 const DefaultableMemberKind Kind = getDefaultableMemberKind(MethodDecl);
40 if (Kind == DefaultableMemberKind::None)
43 return analyzeRecord(MethodDecl->getParent(), Kind, SkipMethods::Yes);
47ExceptionSpecAnalyzer::analyzeFieldDecl(
const FieldDecl *FDecl,
48 DefaultableMemberKind Kind) {
52 if (
const CXXRecordDecl *RecDecl =
53 FDecl->getType()->getUnqualifiedDesugaredType()->getAsCXXRecordDecl())
54 return analyzeRecord(RecDecl, Kind);
57 if (FDecl->getType().isTrivialType(FDecl->getASTContext()))
64ExceptionSpecAnalyzer::analyzeBase(
const CXXBaseSpecifier &Base,
65 DefaultableMemberKind Kind) {
66 const auto *RecType = Base.getType()->getAs<RecordType>();
70 return analyzeRecord(RecType->getAsCXXRecordDecl(), 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)
90 for (
const auto &BaseSpec : RecordDecl->bases()) {
91 const State CurrentState = analyzeBase(BaseSpec, Kind);
95 Result = CurrentState;
98 for (
const auto &BaseSpec : RecordDecl->vbases()) {
99 const State CurrentState = analyzeBase(BaseSpec, Kind);
103 Result = CurrentState;
106 for (
const auto *FDecl : RecordDecl->fields())
107 if (!FDecl->isInvalidDecl() && !FDecl->isUnnamedBitField()) {
108 const State CurrentState = analyzeFieldDecl(FDecl, Kind);
112 Result = CurrentState;
119ExceptionSpecAnalyzer::analyzeImpl(
const FunctionDecl *
FuncDecl) {
120 const auto *FuncProto =
FuncDecl->getType()->getAs<FunctionProtoType>();
124 const ExceptionSpecificationType EST = FuncProto->getExceptionSpecType();
126 if (EST == EST_Unevaluated || (EST == EST_None &&
FuncDecl->isDefaulted()))
127 return analyzeUnresolvedOrDefaulted(cast<CXXMethodDecl>(
FuncDecl),
130 return analyzeFunctionEST(
FuncDecl, FuncProto);
134ExceptionSpecAnalyzer::analyzeFunctionEST(
const FunctionDecl *
FuncDecl,
135 const FunctionProtoType *FuncProto) {
139 if (isUnresolvedExceptionSpec(FuncProto->getExceptionSpecType()))
143 if (isa<CXXDestructorDecl>(
FuncDecl) &&
144 FuncDecl->getExceptionSpecType() == EST_None)
147 switch (FuncProto->canThrow()) {
151 const Expr *NoexceptExpr = FuncProto->getNoexceptExpr();
156 if (NoexceptExpr->isValueDependent())
161 if (NoexceptExpr->EvaluateAsBooleanCondition(
162 Result,
FuncDecl->getASTContext(),
true))
174bool ExceptionSpecAnalyzer::hasTrivialMemberKind(
const CXXRecordDecl *RecDecl,
175 DefaultableMemberKind Kind) {
180 case DefaultableMemberKind::DefaultConstructor:
181 return RecDecl->hasTrivialDefaultConstructor();
182 case DefaultableMemberKind::CopyConstructor:
183 return RecDecl->hasTrivialCopyConstructor();
184 case DefaultableMemberKind::MoveConstructor:
185 return RecDecl->hasTrivialMoveConstructor();
186 case DefaultableMemberKind::CopyAssignment:
187 return RecDecl->hasTrivialCopyAssignment();
188 case DefaultableMemberKind::MoveAssignment:
189 return RecDecl->hasTrivialMoveAssignment();
190 case DefaultableMemberKind::Destructor:
191 return RecDecl->hasTrivialDestructor();
198bool ExceptionSpecAnalyzer::isConstructor(DefaultableMemberKind Kind) {
200 case DefaultableMemberKind::DefaultConstructor:
201 case DefaultableMemberKind::CopyConstructor:
202 case DefaultableMemberKind::MoveConstructor:
210bool ExceptionSpecAnalyzer::isSpecialMember(DefaultableMemberKind Kind) {
212 case DefaultableMemberKind::DefaultConstructor:
213 case DefaultableMemberKind::CopyConstructor:
214 case DefaultableMemberKind::MoveConstructor:
215 case DefaultableMemberKind::CopyAssignment:
216 case DefaultableMemberKind::MoveAssignment:
217 case DefaultableMemberKind::Destructor:
224bool ExceptionSpecAnalyzer::isComparison(DefaultableMemberKind Kind) {
226 case DefaultableMemberKind::CompareEqual:
227 case DefaultableMemberKind::CompareNotEqual:
228 case DefaultableMemberKind::CompareRelational:
229 case DefaultableMemberKind::CompareThreeWay:
236ExceptionSpecAnalyzer::DefaultableMemberKind
237ExceptionSpecAnalyzer::getDefaultableMemberKind(
const FunctionDecl *
FuncDecl) {
238 if (
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(
FuncDecl)) {
239 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(
FuncDecl)) {
240 if (Ctor->isDefaultConstructor())
241 return DefaultableMemberKind::DefaultConstructor;
243 if (Ctor->isCopyConstructor())
244 return DefaultableMemberKind::CopyConstructor;
246 if (Ctor->isMoveConstructor())
247 return DefaultableMemberKind::MoveConstructor;
250 if (MethodDecl->isCopyAssignmentOperator())
251 return DefaultableMemberKind::CopyAssignment;
253 if (MethodDecl->isMoveAssignmentOperator())
254 return DefaultableMemberKind::MoveAssignment;
256 if (isa<CXXDestructorDecl>(
FuncDecl))
257 return DefaultableMemberKind::Destructor;
260 const LangOptions &LangOpts =
FuncDecl->getLangOpts();
262 switch (
FuncDecl->getDeclName().getCXXOverloadedOperator()) {
264 return DefaultableMemberKind::CompareEqual;
266 case OO_ExclaimEqual:
267 return DefaultableMemberKind::CompareNotEqual;
271 if (!LangOpts.CPlusPlus20)
273 return DefaultableMemberKind::CompareThreeWay;
278 case OO_GreaterEqual:
280 if (!LangOpts.CPlusPlus20)
282 return DefaultableMemberKind::CompareRelational;
289 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[]