[clang-tidy] Include constructor initializers in bugprone-exception-escape check

Fixes PR#52435.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D113507
This commit is contained in:
Fabian Wolff 2022-01-20 22:51:53 +01:00
parent e1b7bd911d
commit d3b188a2d7
2 changed files with 61 additions and 0 deletions

View file

@ -119,6 +119,16 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
CallStack.insert(Func);
ExceptionInfo Result =
throwsException(Body, ExceptionInfo::Throwables(), CallStack);
// For a constructor, we also have to check the initializers.
if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Func)) {
for (const CXXCtorInitializer *Init : Ctor->inits()) {
ExceptionInfo Excs = throwsException(
Init->getInit(), ExceptionInfo::Throwables(), CallStack);
Result.merge(Excs);
}
}
CallStack.erase(Func);
return Result;
}
@ -195,6 +205,14 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
ExceptionInfo Excs = throwsException(Func, CallStack);
Results.merge(Excs);
}
} else if (const auto *Construct = dyn_cast<CXXConstructExpr>(St)) {
ExceptionInfo Excs =
throwsException(Construct->getConstructor(), CallStack);
Results.merge(Excs);
} else if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(St)) {
ExceptionInfo Excs =
throwsException(DefaultInit->getExpr(), Caught, CallStack);
Results.merge(Excs);
} else {
for (const Stmt *Child : St->children()) {
ExceptionInfo Excs = throwsException(Child, Caught, CallStack);

View file

@ -288,6 +288,49 @@ int indirectly_recursive(int n) noexcept {
return recursion_helper(n);
}
struct super_throws {
super_throws() noexcept(false) { throw 42; }
};
struct sub_throws : super_throws {
sub_throws() noexcept : super_throws() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws' which should not throw exceptions
};
struct super_throws_again {
super_throws_again() throw(int);
};
struct sub_throws_again : super_throws_again {
sub_throws_again() noexcept : super_throws_again() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws_again' which should not throw exceptions
};
struct init_member_throws {
super_throws s;
init_member_throws() noexcept : s() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'init_member_throws' which should not throw exceptions
};
struct implicit_init_member_throws {
super_throws s;
implicit_init_member_throws() noexcept {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'implicit_init_member_throws' which should not throw exceptions
};
struct init {
explicit init(int, int) noexcept(false) { throw 42; }
};
struct in_class_init_throws {
init i{1, 2};
in_class_init_throws() noexcept {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'in_class_init_throws' which should not throw exceptions
};
int main() {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'main' which should not throw exceptions
throw 1;