I'm currently implementing a clang tool. I have no idea how to find out the noexcept-ness of a function given its clang::FunctionDecl
. For the following code
struct X {
X() = default;
};
int main() {
X x;
}
clang-query
shows that the default constructor of X
is noexcept
:
-CXXConstructorDecl 0x563b8aea50e8 <line:2:3, col:15> col:3 used constexpr X 'void () noexcept' default trivial implicit-inline
`-CompoundStmt 0x563b8aea5768 <col:15>
but fd->getExceptionSpecType()
returns clang::ExceptionSpecificationType::EST_None
. Moreover, I think the noexcept-ness might also be encoded in the function type (since it is part of the function type since C++17), but I don't know how to extract that information.
To get the ExceptionSpecificationType
of a
FunctionDecl
,
call
ValueDecl::getType()
to get its
QualType
,
call getTypePtr()
on that to get its
Type
,
then use
dyn_cast
to downcast that to a
FunctionProtoType
,
and finally call
FunctionProtoType::getExceptionSpecType()
.
For example:
clang::FunctionDecl const *functionDecl = /*wherever*/;
clang::Type const *type = functionDecl->getType().getTypePtr();
if (auto fpt = dyn_cast<clang::FunctionProtoType>(type)) {
clang::ExceptionSpecificationType est = fpt->getExceptionSpecType();
// Now do something with 'est'.
}
On your example, for X::X()
, the above yields EST_BasicNoexcept
.
(I'm using Clang+LLVM-16.0.0 on Linux, but this should be the same across a fairly wide range of versions.)
The documentation for FunctionDecl::getExceptionSpecType()
says:
Gets the ExceptionSpecificationType as declared.
The "as declared" part means it only includes noexcept
if that was
syntactically present.
In contrast, by going through the FunctionProtoType
, we get implicit
exception specifications too.
If you remove the main
function from the example, then the above
snippet instead yields EST_Unevaluated
, whose documentation says:
not evaluated yet, for special member function
Digging through the sources (e.g.,
SemaExceptionSpec.cpp:1056
,
etc.), it seems that implicit exception specifications for constructors
and the like are not computed until needed. A call site is a "need", as
is a virtual override, perhaps among a few other cases.
If you want to go deeper on exception specifications, you may want to
look at
ExceptionAnalyzer.cpp
in the Clang sources, since that does a bunch of analysis of exception
specification semantics.