c++clangllvmnoexceptlibtooling

How to get noexcept-ness of a FunctionDecl in clang?


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.


Solution

  • 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.)

    Why doesn't FunctionDecl::getExceptionSpecType work?

    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.

    Caveat: Unevaluated exception specifications

    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.

    Supplementary

    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.