Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -3313,6 +3313,12 @@ CINDEX_LINKAGE unsigned clang_Cursor_isFunctionInlined(CXCursor C); /** + * \brief Determine whether a CXCursor that is a function declaration, is + * marked with __attribute__((noreturn)), [[gnu::noreturn]], or [[noreturn]]. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isFunctionNoReturn(CXCursor C); + +/** * \brief Determine whether a CXType has the "volatile" qualifier set, * without looking through typedefs that may have added "volatile" at * a different level. Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -3545,6 +3545,15 @@ return FD->isInlined(); } +unsigned clang_Cursor_isFunctionNoReturn(CXCursor C) { + const Decl *D = getCursorDecl(C); + const FunctionDecl *FD = dyn_cast_or_null(D); + if (!FD) { + return false; + } + return FD->isNoReturn(); +} + static StringLiteral* getCFSTR_value(CallExpr *callExpr) { if (callExpr->getNumArgs() != 1) { return nullptr; Index: unittests/libclang/LibclangTest.cpp =================================================================== --- unittests/libclang/LibclangTest.cpp +++ unittests/libclang/LibclangTest.cpp @@ -460,6 +460,36 @@ clang_disposeSourceRangeList(Ranges); } +TEST_F(LibclangParseTest, clang_Cursor_isFunctionNoReturn) { + std::string headerFile = "header.h"; + WriteFile(headerFile, + "void fatal_error() __attribute__((noreturn));\n" + "void non_fatal_error();\n"); + + ClangTU = clang_parseTranslationUnit(Index, headerFile.c_str(), + nullptr, 0, nullptr, 0, TUFlags); + + __block unsigned nonFatalIsNoReturn = 0, fatalIsNoReturn = 0; + + clang_visitChildrenWithBlock(clang_getTranslationUnitCursor(ClangTU), + ^enum CXChildVisitResult(CXCursor cursor, CXCursor parent) { + if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) { + CXString displayNameCX = clang_getCursorDisplayName(cursor); + std::string displayName = clang_getCString(displayNameCX); + if (displayName == "non_fatal_error") { + nonFatalIsNoReturn = clang_Cursor_isFunctionNoReturn(cursor); + } else if (displayName == "fatal_error") { + fatalIsNoReturn = clang_Cursor_isFunctionNoReturn(cursor); + } + clang_disposeString(displayNameCX); + } + return CXChildVisit_Continue; + }); + + ASSERT_TRUE(fatalIsNoReturn); + ASSERT_FALSE(nonFatalIsNoReturn); +} + class LibclangReparseTest : public LibclangParseTest { public: void DisplayDiagnostics() {