https://github.com/jbcoe updated https://github.com/llvm/llvm-project/pull/188965
>From e8eee3a13213f8262e3d46c22d97ece7c09af6db Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" <[email protected]> Date: Fri, 27 Mar 2026 10:59:40 +0000 Subject: [PATCH 1/2] [libclang] Add support for constexpr declarations in Python bindings and C API --- clang/bindings/python/clang/cindex.py | 9 ++++ .../python/tests/cindex/test_constexpr.py | 54 +++++++++++++++++++ clang/include/clang-c/Index.h | 6 +++ clang/tools/libclang/CIndex.cpp | 9 ++++ clang/tools/libclang/libclang.map | 1 + 5 files changed, 79 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_constexpr.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index b71f9ed2275e0..d86f7d07296dd 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -2375,6 +2375,14 @@ def is_function_inlined(self) -> bool: """ return bool(conf.lib.clang_Cursor_isFunctionInlined(self)) + @property + @cursor_null_guard + def is_constexpr(self) -> bool: + """ + Determine if the cursor is a constexpr declaration. + """ + return bool(conf.lib.clang_Cursor_isConstexpr(self)) + @cursor_null_guard def has_attrs(self) -> bool: """ @@ -4492,6 +4500,7 @@ def set_property(self, property, value): ("clang_Cursor_isAnonymousRecordDecl", [Cursor], c_uint), ("clang_Cursor_isBitField", [Cursor], c_uint), ("clang_Cursor_isFunctionInlined", [Cursor], c_uint), + ("clang_Cursor_isConstexpr", [Cursor], c_uint), ("clang_Location_isInSystemHeader", [SourceLocation], c_int), ("clang_PrintingPolicy_dispose", [PrintingPolicy]), ("clang_PrintingPolicy_getProperty", [PrintingPolicy, c_int], c_uint), diff --git a/clang/bindings/python/tests/cindex/test_constexpr.py b/clang/bindings/python/tests/cindex/test_constexpr.py new file mode 100644 index 0000000000000..cb3db25929f1c --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_constexpr.py @@ -0,0 +1,54 @@ +import unittest +from .util import get_cursor, get_tu + +class TestConstexpr(unittest.TestCase): + def test_is_constexpr(self): + source = """ + constexpr int f1() { + constexpr int local_v1 = 1; + int local_v2 = 2; + return local_v1 + local_v2; + } + int f2() { return 2; } + + constexpr int v1 = 3; + int v2 = 4; + + struct S { + static constexpr int m1 = 5; + int m2; + constexpr int m3() const { return 6; } + int m4() const { return 7; } + }; + """ + tu = get_tu(source, lang="cpp") + + f1 = get_cursor(tu, "f1") + f2 = get_cursor(tu, "f2") + self.assertIsNotNone(f1) + self.assertTrue(f1.is_constexpr) + self.assertFalse(f2.is_constexpr) + + v1 = get_cursor(tu, "v1") + v2 = get_cursor(tu, "v2") + self.assertIsNotNone(v1) + self.assertTrue(v1.is_constexpr) + self.assertFalse(v2.is_constexpr) + + local_v1 = get_cursor(f1, "local_v1") + local_v2 = get_cursor(f1, "local_v2") + self.assertIsNotNone(local_v1) + self.assertTrue(local_v1.is_constexpr) + self.assertFalse(local_v2.is_constexpr) + + S = get_cursor(tu, "S") + m1 = get_cursor(S, "m1") + m2 = get_cursor(S, "m2") + m3 = get_cursor(S, "m3") + m4 = get_cursor(S, "m4") + + self.assertIsNotNone(m1) + self.assertTrue(m1.is_constexpr) + self.assertFalse(m2.is_constexpr) + self.assertTrue(m3.is_constexpr) + self.assertFalse(m4.is_constexpr) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index dcf1f4f1b4258..b657fdb7979e2 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3351,6 +3351,12 @@ CINDEX_LINKAGE unsigned clang_Cursor_isMacroBuiltin(CXCursor C); */ CINDEX_LINKAGE unsigned clang_Cursor_isFunctionInlined(CXCursor C); +/** + * Determine whether a CXCursor that is a function or variable declaration is + * a constexpr declaration. + */ +CINDEX_LINKAGE unsigned clang_Cursor_isConstexpr(CXCursor C); + /** * Determine whether a CXType has the "volatile" qualifier set, * without looking through typedefs that may have added "volatile" at diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 3ee37ed2dfc27..ba01a119d26a4 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -4559,6 +4559,15 @@ unsigned clang_Cursor_isFunctionInlined(CXCursor C) { return FD->isInlined(); } +unsigned clang_Cursor_isConstexpr(CXCursor C) { + const Decl *D = getCursorDecl(C); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) + return FD->isConstexpr(); + if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(D)) + return VD->isConstexpr(); + return false; +} + static StringLiteral *getCFSTR_value(CallExpr *callExpr) { if (callExpr->getNumArgs() != 1) { return nullptr; diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map index 3d9d2e268a611..de22123e1f2a8 100644 --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -87,6 +87,7 @@ LLVM_13 { clang_Cursor_isDynamicCall; clang_Cursor_isExternalSymbol; clang_Cursor_isFunctionInlined; + clang_Cursor_isConstexpr; clang_Cursor_isInlineNamespace; clang_Cursor_isMacroBuiltin; clang_Cursor_isMacroFunctionLike; >From 46aa9189219e347637f7ef6d26e40dea556bb90a Mon Sep 17 00:00:00 2001 From: "Jonathan B. Coe" <[email protected]> Date: Fri, 27 Mar 2026 11:10:29 +0000 Subject: [PATCH 2/2] Fix python test formatting. --- clang/bindings/python/tests/cindex/test_constexpr.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/bindings/python/tests/cindex/test_constexpr.py b/clang/bindings/python/tests/cindex/test_constexpr.py index cb3db25929f1c..6b5f3ad3ba9c1 100644 --- a/clang/bindings/python/tests/cindex/test_constexpr.py +++ b/clang/bindings/python/tests/cindex/test_constexpr.py @@ -1,6 +1,7 @@ import unittest from .util import get_cursor, get_tu + class TestConstexpr(unittest.TestCase): def test_is_constexpr(self): source = """ @@ -22,7 +23,7 @@ def test_is_constexpr(self): }; """ tu = get_tu(source, lang="cpp") - + f1 = get_cursor(tu, "f1") f2 = get_cursor(tu, "f2") self.assertIsNotNone(f1) @@ -34,7 +35,7 @@ def test_is_constexpr(self): self.assertIsNotNone(v1) self.assertTrue(v1.is_constexpr) self.assertFalse(v2.is_constexpr) - + local_v1 = get_cursor(f1, "local_v1") local_v2 = get_cursor(f1, "local_v2") self.assertIsNotNone(local_v1) @@ -46,7 +47,7 @@ def test_is_constexpr(self): m2 = get_cursor(S, "m2") m3 = get_cursor(S, "m3") m4 = get_cursor(S, "m4") - + self.assertIsNotNone(m1) self.assertTrue(m1.is_constexpr) self.assertFalse(m2.is_constexpr) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
