[clang] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-15 Thread Dmitry Fursov via cfe-commits

https://github.com/fursov created 
https://github.com/llvm/llvm-project/pull/108769

If the type of an enumeration is not native (e.g. uint8_t) but is unsigned then 
evaluation of the value might get wrong: for values bigger than half of type 
range the return value will be negative. This happens because for non-native 
enum types the TypeKind is ELABORATED. To get the real integer type, the 
conversion to canonical type is required before the enum_value() function can 
decide about type being signed or unsigned.

This is fix for ticket #108766: 
https://github.com/llvm/llvm-project/issues/108766

>From 800010fabe3160e701ff58f7789dd9e01c80451f Mon Sep 17 00:00:00 2001
From: Dmitry Fursov 
Date: Sun, 15 Sep 2024 18:14:48 +0300
Subject: [PATCH] Fix evaluation of the unsigned enumeration values

If the type of an enumeration is not native (e.g. uint8_t) but
is unsigned then evaluation of the value might get wrong: for
values bigger than half of type range the return value will be
negative. This happens because for non-native enum types the TypeKind
is ELABORATED. To get the real integer type, the conversion to
canonical type is required before the enum_value() function can
decide about type being signed or unsigned.
---
 clang/bindings/python/clang/cindex.py |  2 ++
 .../python/tests/cindex/test_cursor.py| 19 +++
 2 files changed, 21 insertions(+)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 4da99e899e7f7c..c582c82ce50789 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -1952,6 +1952,8 @@ def enum_value(self):
 underlying_type = self.type
 if underlying_type.kind == TypeKind.ENUM:
 underlying_type = underlying_type.get_declaration().enum_type
+if underlying_type.kind == TypeKind.ELABORATED:
+underlying_type = underlying_type.get_canonical()
 if underlying_type.kind in (
 TypeKind.CHAR_U,
 TypeKind.UCHAR,
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py 
b/clang/bindings/python/tests/cindex/test_cursor.py
index 7476947bde2ea6..61a7bc1414f235 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -570,6 +570,25 @@ def test_enum_values_cpp(self):
 self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
 self.assertEqual(ham.enum_value, 0x100)
 
+def test_enum_values_on_elaborated_type(self):
+tu = get_tu(
+"using myUType = unsigned char; enum TEST : myUType { SPAM = 1, 
HAM = 0xff;", lang="cpp"
+)
+enum = get_cursor(tu, "TEST")
+self.assertIsNotNone(enum)
+
+self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
+
+enum_constants = list(enum.get_children())
+self.assertEqual(len(enum_constants), 2)
+
+spam, ham = enum_constants
+
+self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
+self.assertEqual(spam.enum_value, 1)
+self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
+self.assertEqual(ham.enum_value, 255)
+
 def test_annotation_attribute(self):
 tu = get_tu(
 'int foo (void) __attribute__ ((annotate("here be annotation 
attribute")));'

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-17 Thread Dmitry Fursov via cfe-commits

fursov wrote:

@DeinAlptraum, thank you for the review. The findings are fixed now.
Could you say if the fix to be backported to other relelases, like 18.x or 
19rc? If yes, how this is done?

https://github.com/llvm/llvm-project/pull/108769
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-22 Thread Dmitry Fursov via cfe-commits


@@ -1952,6 +1952,8 @@ def enum_value(self):
 underlying_type = self.type
 if underlying_type.kind == TypeKind.ENUM:
 underlying_type = underlying_type.get_declaration().enum_type
+if underlying_type.kind == TypeKind.ELABORATED:

fursov wrote:

I ran the check-clang-python tests using clang 15 - it also does not resolve 
the enum type to the integer types. But since there was no elaborated type yet, 
it returns TypeKind.TYPEDEF instead (that matches the godbolt example from 
above - the TUintType in clang15 - typedef, in clang16 - elaborated and only 
then typedef).
The test like in patch above (test_enum_values_on_elaborated_type) fails same 
way as on "main" branch:

```
self.assertEqual(ham.enum_value, 255)
AssertionError: -1 != 255
```

https://github.com/llvm/llvm-project/pull/108769
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-21 Thread Dmitry Fursov via cfe-commits

https://github.com/fursov edited 
https://github.com/llvm/llvm-project/pull/108769
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-21 Thread Dmitry Fursov via cfe-commits


@@ -1952,6 +1952,8 @@ def enum_value(self):
 underlying_type = self.type
 if underlying_type.kind == TypeKind.ENUM:
 underlying_type = underlying_type.get_declaration().enum_type
+if underlying_type.kind == TypeKind.ELABORATED:

fursov wrote:

My educated guess:

the call chain looks like this: enum_type (cindex.py) -> 
clang_getEnumDeclIntegerType (clang/tools/libclang/CXType.cpp) -> 
getIntegerType (clang/include/clang/AST/Decl.h)

Let's use this example:

`using TUintType = uint8_t;

enum class ETUintType : TUintType
{
A = 0xff,
B = 0x20
};
`

>From what I can see, e.g. from ast dumper (clang/lib/AST/TextNodeDumper.cpp, 
>TextNodeDumper::VisitEnumDecl), first it dumps scoped class, then name 
>(ETUintType), then it uses function dumpType() to print the type: first, the 
>one that has been provided by getIntegerType(), but then it is desugared.

EnumDecl 0x5580b1f62490  line:5:12 class ETUintType 
'TUintType':'unsigned char'

This leads me to the conclusion, that getIntegerType() on the AST parser on 
purpose returns whatever type that enum is defined against without resolving to 
the target canonical type.

But I would like to hear the opinion from experts.

https://github.com/llvm/llvm-project/pull/108769
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-22 Thread Dmitry Fursov via cfe-commits


@@ -1952,6 +1952,8 @@ def enum_value(self):
 underlying_type = self.type
 if underlying_type.kind == TypeKind.ENUM:
 underlying_type = underlying_type.get_declaration().enum_type
+if underlying_type.kind == TypeKind.ELABORATED:

fursov wrote:

@Endilll , do you think the getIntegerType function on the EnumDecl class 
should return the true integer type to which any sugared type resolves?

https://github.com/llvm/llvm-project/pull/108769
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-18 Thread Dmitry Fursov via cfe-commits

fursov wrote:

Sorry, I'm not familiar with the process (this is my first PR on github) - how 
the change gets now to the repo? Someone from llvm-project should push it?

https://github.com/llvm/llvm-project/pull/108769
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libclang/python] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-18 Thread Dmitry Fursov via cfe-commits

https://github.com/fursov updated 
https://github.com/llvm/llvm-project/pull/108769

>From 4d9f2e2e9ac57b4279a4aafc078a3b4fb3ff646f Mon Sep 17 00:00:00 2001
From: Dmitry Fursov 
Date: Sun, 15 Sep 2024 18:14:48 +0300
Subject: [PATCH 1/2] Fix evaluation of the unsigned enumeration values

If the type of an enumeration is not native (e.g. uint8_t) but
is unsigned then evaluation of the value might get wrong: for
values bigger than half of type range the return value will be
negative. This happens because for non-native enum types the TypeKind
is ELABORATED. To get the real integer type, the conversion to
canonical type is required before the enum_value() function can
decide about type being signed or unsigned.
---
 clang/bindings/python/clang/cindex.py |  2 ++
 .../python/tests/cindex/test_cursor.py| 20 +++
 2 files changed, 22 insertions(+)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 4da99e899e7f7c..c582c82ce50789 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -1952,6 +1952,8 @@ def enum_value(self):
 underlying_type = self.type
 if underlying_type.kind == TypeKind.ENUM:
 underlying_type = underlying_type.get_declaration().enum_type
+if underlying_type.kind == TypeKind.ELABORATED:
+underlying_type = underlying_type.get_canonical()
 if underlying_type.kind in (
 TypeKind.CHAR_U,
 TypeKind.UCHAR,
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py 
b/clang/bindings/python/tests/cindex/test_cursor.py
index 7476947bde2ea6..927e35993a1c37 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -570,6 +570,26 @@ def test_enum_values_cpp(self):
 self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
 self.assertEqual(ham.enum_value, 0x100)
 
+def test_enum_values_on_elaborated_type(self):
+tu = get_tu(
+"using myUType = unsigned char; enum TEST : myUType { SPAM = 1, 
HAM = 0xff; }",
+lang="cpp",
+)
+enum = get_cursor(tu, "TEST")
+self.assertIsNotNone(enum)
+
+self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
+
+enum_constants = list(enum.get_children())
+self.assertEqual(len(enum_constants), 2)
+
+spam, ham = enum_constants
+
+self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
+self.assertEqual(spam.enum_value, 1)
+self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
+self.assertEqual(ham.enum_value, 255)
+
 def test_annotation_attribute(self):
 tu = get_tu(
 'int foo (void) __attribute__ ((annotate("here be annotation 
attribute")));'

>From 683d2aaac80c715eea298eb1f65f05959fd320f6 Mon Sep 17 00:00:00 2001
From: Dmitry Fursov 
Date: Wed, 18 Sep 2024 13:57:56 +0300
Subject: [PATCH 2/2] Update clang/bindings/python/tests/cindex/test_cursor.py

Co-authored-by: Jannick Kremer 
---
 clang/bindings/python/tests/cindex/test_cursor.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/bindings/python/tests/cindex/test_cursor.py 
b/clang/bindings/python/tests/cindex/test_cursor.py
index 927e35993a1c37..24ce15ba786428 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -572,7 +572,7 @@ def test_enum_values_cpp(self):
 
 def test_enum_values_on_elaborated_type(self):
 tu = get_tu(
-"using myUType = unsigned char; enum TEST : myUType { SPAM = 1, 
HAM = 0xff; }",
+"using myUType = unsigned char; enum TEST : myUType { SPAM = 1, 
HAM = 0xff };",
 lang="cpp",
 )
 enum = get_cursor(tu, "TEST")

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix evaluation of the unsigned enumeration values, #108766 (PR #108769)

2024-09-17 Thread Dmitry Fursov via cfe-commits

https://github.com/fursov updated 
https://github.com/llvm/llvm-project/pull/108769

>From 4d9f2e2e9ac57b4279a4aafc078a3b4fb3ff646f Mon Sep 17 00:00:00 2001
From: Dmitry Fursov 
Date: Sun, 15 Sep 2024 18:14:48 +0300
Subject: [PATCH] Fix evaluation of the unsigned enumeration values

If the type of an enumeration is not native (e.g. uint8_t) but
is unsigned then evaluation of the value might get wrong: for
values bigger than half of type range the return value will be
negative. This happens because for non-native enum types the TypeKind
is ELABORATED. To get the real integer type, the conversion to
canonical type is required before the enum_value() function can
decide about type being signed or unsigned.
---
 clang/bindings/python/clang/cindex.py |  2 ++
 .../python/tests/cindex/test_cursor.py| 20 +++
 2 files changed, 22 insertions(+)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 4da99e899e7f7c..c582c82ce50789 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -1952,6 +1952,8 @@ def enum_value(self):
 underlying_type = self.type
 if underlying_type.kind == TypeKind.ENUM:
 underlying_type = underlying_type.get_declaration().enum_type
+if underlying_type.kind == TypeKind.ELABORATED:
+underlying_type = underlying_type.get_canonical()
 if underlying_type.kind in (
 TypeKind.CHAR_U,
 TypeKind.UCHAR,
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py 
b/clang/bindings/python/tests/cindex/test_cursor.py
index 7476947bde2ea6..927e35993a1c37 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -570,6 +570,26 @@ def test_enum_values_cpp(self):
 self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
 self.assertEqual(ham.enum_value, 0x100)
 
+def test_enum_values_on_elaborated_type(self):
+tu = get_tu(
+"using myUType = unsigned char; enum TEST : myUType { SPAM = 1, 
HAM = 0xff; }",
+lang="cpp",
+)
+enum = get_cursor(tu, "TEST")
+self.assertIsNotNone(enum)
+
+self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
+
+enum_constants = list(enum.get_children())
+self.assertEqual(len(enum_constants), 2)
+
+spam, ham = enum_constants
+
+self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
+self.assertEqual(spam.enum_value, 1)
+self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
+self.assertEqual(ham.enum_value, 255)
+
 def test_annotation_attribute(self):
 tu = get_tu(
 'int foo (void) __attribute__ ((annotate("here be annotation 
attribute")));'

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits