xref: /llvm-project/lldb/test/API/lang/cpp/const_static_integral_member/TestConstStaticIntegralMember.py (revision bc368e4b578730bf0b10acd5412e476ccf7a5807)
1"""
2Tests const static data members as specified by C++11 [class.static.data]p3.
3"""
4
5import lldb
6from lldbsuite.test.decorators import *
7from lldbsuite.test.lldbtest import *
8from lldbsuite.test import lldbutil
9
10
11class TestCase(TestBase):
12    def test(self):
13        self.build()
14        lldbutil.run_to_source_breakpoint(
15            self, "// break here", lldb.SBFileSpec("main.cpp")
16        )
17
18        # Test using a simple const static integer member.
19        self.expect_expr("A::int_val", result_value="1")
20
21        # Try accessing the int member via some expressions that still produce
22        # an lvalue.
23        self.expect_expr("a.int_val", result_value="1")
24        self.expect_expr("(A::int_val)", result_value="1")
25        self.expect_expr("+A::int_val", result_value="1")
26        self.expect_expr("1,A::int_val", result_value="1")
27        self.expect_expr("true ? A::int_val : A::int_val", result_value="1")
28
29        # Test a simple integer member that was also defined in a namespace
30        # scope and has an address.
31        self.expect_expr("A::int_val_with_address", result_value="2")
32
33        # Test a bool member.
34        self.expect_expr("A::bool_val", result_value="true")
35
36        # Test that minimum and maximum values for each data type are right.
37        self.expect_expr("A::char_max == char_max", result_value="true")
38        self.expect_expr("A::schar_max == schar_max", result_value="true")
39        self.expect_expr("A::uchar_max == uchar_max", result_value="true")
40        self.expect_expr("A::int_max == int_max", result_value="true")
41        self.expect_expr("A::uint_max == uint_max", result_value="true")
42        self.expect_expr("A::long_max == long_max", result_value="true")
43        self.expect_expr("A::ulong_max == ulong_max", result_value="true")
44        self.expect_expr("A::longlong_max == longlong_max", result_value="true")
45        self.expect_expr("A::ulonglong_max == ulonglong_max", result_value="true")
46        self.expect_expr("A::wchar_max == wchar_max", result_value="true")
47
48        self.expect_expr("A::char_min == char_min", result_value="true")
49        self.expect_expr("A::schar_min == schar_min", result_value="true")
50        self.expect_expr("A::uchar_min == uchar_min", result_value="true")
51        self.expect_expr("A::int_min == int_min", result_value="true")
52        self.expect_expr("A::uint_min == uint_min", result_value="true")
53        self.expect_expr("A::long_min == long_min", result_value="true")
54        self.expect_expr("A::ulong_min == ulong_min", result_value="true")
55        self.expect_expr("A::longlong_min == longlong_min", result_value="true")
56        self.expect_expr("A::ulonglong_min == ulonglong_min", result_value="true")
57        self.expect_expr("A::wchar_min == wchar_min", result_value="true")
58
59        # Test an unscoped enum.
60        self.expect_expr("A::enum_val", result_value="enum_case2")
61        # Test an unscoped enum with bool as the underlying type.
62        self.expect_expr("A::enum_bool_val", result_value="enum_bool_case1")
63
64        # Test a scoped enum.
65        self.expect_expr("A::scoped_enum_val", result_value="scoped_enum_case2")
66        # Test an scoped enum with a value that isn't an enumerator.
67        self.expect_expr(
68            "A::not_enumerator_scoped_enum_val", result_value="scoped_enum_case1 | 0x4"
69        )
70        # This time with more than one enum value plus the extra.
71        self.expect_expr(
72            "A::not_enumerator_scoped_enum_val_2",
73            result_value="scoped_enum_case1 | scoped_enum_case2 | 0x4",
74        )
75
76        # Test an enum with fixed underlying type.
77        self.expect_expr("A::scoped_char_enum_val", result_value="case2")
78        self.expect_expr("A::scoped_ll_enum_val_neg", result_value="case0")
79        self.expect_expr("A::scoped_ll_enum_val", result_value="case2")
80
81        # Test taking address.
82        if lldbplatformutil.getPlatform() == "windows":
83            # On Windows data members without the out-of-class definitions still have
84            # valid adresses and the following expression works fine.
85            self.expect_expr("const int *i = &A::int_val; *i", result_value="1")
86        else:
87            # On other platforms (Linux, macos) data members without the out-of-class
88            # definitions don't have valid addresses and the following code produces
89            # a linker error.
90            self.expect(
91                "expr const int *i = &A::int_val; *i",
92                error=True,
93                substrs=["Couldn't look up symbols:"],
94            )
95
96        # This should work on all platforms.
97        self.expect_expr(
98            "const int *i = &A::int_val_with_address; *i", result_value="2"
99        )
100
101        # Printing the whole type takes a slightly different code path. Check that
102        # it does not crash.
103        self.expect("image lookup -t A")
104
105    # dsymutil strips the debug info for classes that only have const static
106    # data members without locations.
107    @expectedFailureAll(debug_info=["dsym"], dwarf_version=["<", "5"])
108    def test_class_with_only_const_static(self):
109        self.build()
110        lldbutil.run_to_source_breakpoint(
111            self, "// break here", lldb.SBFileSpec("main.cpp")
112        )
113
114        self.expect_expr("ClassWithOnlyConstStatic::member", result_value="3")
115
116    def check_global_var(self, name: str, expect_type, expect_val):
117        var_list = self.target().FindGlobalVariables(name, lldb.UINT32_MAX)
118        self.assertGreaterEqual(len(var_list), 1)
119        varobj = var_list[0]
120        self.assertEqual(varobj.type.name, expect_type)
121        self.assertEqual(varobj.value, expect_val)
122
123    def check_inline_static_members(self, flags):
124        self.build(dictionary={"CXXFLAGS_EXTRAS": flags})
125        lldbutil.run_to_source_breakpoint(
126            self, "// break here", lldb.SBFileSpec("main.cpp")
127        )
128
129        self.check_global_var("A::int_val", "const int", "1")
130        self.check_global_var("A::int_val_with_address", "const int", "2")
131        self.check_global_var("A::inline_int_val", "const int", "3")
132        self.check_global_var("A::bool_val", "const bool", "true")
133        self.check_global_var("A::enum_val", "Enum", "enum_case2")
134        self.check_global_var("A::enum_bool_val", "EnumBool", "enum_bool_case1")
135        self.check_global_var("A::scoped_enum_val", "ScopedEnum", "scoped_enum_case2")
136
137        self.check_global_var("ClassWithOnlyConstStatic::member", "const int", "3")
138
139        self.check_global_var("ClassWithConstexprs::member", "const int", "2")
140        self.check_global_var("ClassWithConstexprs::enum_val", "Enum", "enum_case2")
141        self.check_global_var(
142            "ClassWithConstexprs::scoped_enum_val", "ScopedEnum", "scoped_enum_case2"
143        )
144
145    # Fails on Windows for unknown reasons.
146    @skipIfWindows
147    # On linux this passes due to the manual index
148    @expectedFailureDarwin(debug_info=no_match(["dsym"]))
149    @skipIf(debug_info=["dsym"], compiler=["clang"], compiler_version=["<", "19.0"])
150    def test_inline_static_members_dwarf5(self):
151        self.check_inline_static_members("-gdwarf-5")
152
153    # On linux this passes due to the manual index
154    @expectedFailureDarwin
155    def test_inline_static_members_dwarf4(self):
156        self.check_inline_static_members("-gdwarf-4")
157
158    # With older versions of Clang, LLDB fails to evaluate classes with only
159    # constexpr members when dsymutil is enabled
160    @expectedFailureAll(
161        debug_info=["dsym"], compiler=["clang"], compiler_version=["<", "14.0"]
162    )
163    def test_class_with_only_constexpr_static(self):
164        self.build()
165        lldbutil.run_to_source_breakpoint(
166            self, "// break here", lldb.SBFileSpec("main.cpp")
167        )
168
169        # Test `constexpr static`.
170        self.expect_expr("ClassWithConstexprs::member", result_value="2")
171        self.expect_expr("ClassWithConstexprs::enum_val", result_value="enum_case2")
172        self.expect_expr(
173            "ClassWithConstexprs::scoped_enum_val", result_value="scoped_enum_case2"
174        )
175
176        # Test an aliased enum with fixed underlying type.
177        self.expect_expr(
178            "ClassWithEnumAlias::enum_alias", result_value="scoped_enum_case2"
179        )
180        self.expect_expr(
181            "ClassWithEnumAlias::enum_alias_alias", result_value="scoped_enum_case1"
182        )
183
184    def check_shadowed_static_inline_members(self, flags):
185        """Tests that the expression evaluator and SBAPI can both
186        correctly determine the requested inline static variable
187        in the presence of multiple variables of the same name."""
188
189        self.build(dictionary={"CXXFLAGS_EXTRAS": flags})
190        lldbutil.run_to_name_breakpoint(self, "bar")
191
192        self.check_global_var("ns::Foo::mem", "const int", "10")
193
194        self.expect_expr("mem", result_value="10")
195        self.expect_expr("Foo::mem", result_value="10")
196        self.expect_expr("ns::Foo::mem", result_value="10")
197        self.expect_expr("::Foo::mem", result_value="-29")
198
199    # Fails on Windows for unknown reasons.
200    @skipIfWindows
201    # On linux this passes due to the manual index
202    @expectedFailureDarwin(debug_info=no_match(["dsym"]))
203    @skipIf(debug_info=["dsym"], compiler=["clang"], compiler_version=["<", "19.0"])
204    def test_shadowed_static_inline_members_dwarf5(self):
205        self.check_shadowed_static_inline_members("-gdwarf-5")
206
207    # On linux this passes due to the manual index
208    @expectedFailureDarwin
209    def test_shadowed_static_inline_members_dwarf4(self):
210        self.check_shadowed_static_inline_members("-gdwarf-4")
211
212    @expectedFailureAll(bugnumber="target var doesn't honour global namespace")
213    def test_shadowed_static_inline_members_xfail(self):
214        self.build()
215        lldbutil.run_to_name_breakpoint(self, "bar")
216        self.check_global_var("::Foo::mem", "const int", "-29")
217