packaging: add --disable-experimental-malloc
[platform/upstream/glibc.git] / support / tst-glibcpp.py
1 #! /usr/bin/python3
2 # Tests for scripts/glibcpp.py
3 # Copyright (C) 2022-2023 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
5 #
6 # The GNU C Library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
10 #
11 # The GNU C Library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with the GNU C Library; if not, see
18 # <https://www.gnu.org/licenses/>.
19
20 import inspect
21 import sys
22
23 import glibcpp
24
25 # Error counter.
26 errors = 0
27
28 class TokenizerErrors:
29     """Used as the error reporter during tokenization."""
30
31     def __init__(self):
32         self.errors = []
33
34     def error(self, token, message):
35         self.errors.append((token, message))
36
37 def check_macro_definitions(source, expected):
38     reporter = TokenizerErrors()
39     tokens = glibcpp.tokenize_c(source, reporter)
40
41     actual = []
42     for md in glibcpp.macro_definitions(tokens):
43         if md.function:
44             md_name = '{}({})'.format(md.name, ','.join(md.args_lowered))
45         else:
46             md_name = md.name
47         actual.append((md_name, md.body_lowered))
48
49     if actual != expected or reporter.errors:
50         global errors
51         errors += 1
52         # Obtain python source line information.
53         frame = inspect.stack(2)[1]
54         print('{}:{}: error: macro definition mismatch, actual definitions:'
55               .format(frame[1], frame[2]))
56         for md in actual:
57             print('note: {} {!r}'.format(md[0], md[1]))
58
59         if reporter.errors:
60             for err in reporter.errors:
61                 print('note: tokenizer error: {}: {}'.format(
62                     err[0].line, err[1]))
63
64 def check_macro_eval(source, expected, expected_errors=''):
65     reporter = TokenizerErrors()
66     tokens = list(glibcpp.tokenize_c(source, reporter))
67
68     if reporter.errors:
69         # Obtain python source line information.
70         frame = inspect.stack(2)[1]
71         for err in reporter.errors:
72             print('{}:{}: tokenizer error: {}: {}'.format(
73                 frame[1], frame[2], err[0].line, err[1]))
74         return
75
76     class EvalReporter:
77         """Used as the error reporter during evaluation."""
78
79         def __init__(self):
80             self.lines = []
81
82         def error(self, line, message):
83             self.lines.append('{}: error: {}\n'.format(line, message))
84
85         def note(self, line, message):
86             self.lines.append('{}: note: {}\n'.format(line, message))
87
88     reporter = EvalReporter()
89     actual = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter)
90     actual_errors = ''.join(reporter.lines)
91     if actual != expected or actual_errors != expected_errors:
92         global errors
93         errors += 1
94         # Obtain python source line information.
95         frame = inspect.stack(2)[1]
96         print('{}:{}: error: macro evaluation mismatch, actual results:'
97               .format(frame[1], frame[2]))
98         for k, v in actual.items():
99             print('  {}: {!r}'.format(k, v))
100         for msg in reporter.lines:
101             sys.stdout.write('  | ' + msg)
102
103 # Individual test cases follow.
104
105 check_macro_definitions('', [])
106 check_macro_definitions('int main()\n{\n{\n', [])
107 check_macro_definitions("""
108 #define A 1
109 #define B 2 /* ignored */
110 #define C 3 // also ignored
111 #define D \
112  4
113 #define STRING "string"
114 #define FUNCLIKE(a, b) (a + b)
115 #define FUNCLIKE2(a, b) (a + \
116  b)
117 """, [('A', ['1']),
118       ('B', ['2']),
119       ('C', ['3']),
120       ('D', ['4']),
121       ('STRING', ['"string"']),
122       ('FUNCLIKE(a,b)', list('(a+b)')),
123       ('FUNCLIKE2(a,b)', list('(a+b)')),
124       ])
125 check_macro_definitions('#define MACRO', [('MACRO', [])])
126 check_macro_definitions('#define MACRO\n', [('MACRO', [])])
127 check_macro_definitions('#define MACRO()', [('MACRO()', [])])
128 check_macro_definitions('#define MACRO()\n', [('MACRO()', [])])
129
130 check_macro_eval('#define A 1', {'A': 1})
131 check_macro_eval('#define A (1)', {'A': 1})
132 check_macro_eval('#define A (1 + 1)', {'A': 2})
133 check_macro_eval('#define A (1U << 31)', {'A': 1 << 31})
134 check_macro_eval('#define A (1 | 2)', {'A': 1 | 2})
135 check_macro_eval('''\
136 #define A (B + 1)
137 #define B 10
138 #define F(x) ignored
139 #define C "not ignored"
140 ''', {
141     'A': 11,
142     'B': 10,
143     'C': '"not ignored"',
144 })
145
146 # Checking for evaluation errors.
147 check_macro_eval('''\
148 #define A 1
149 #define A 2
150 ''', {
151     'A': 1,
152 }, '''\
153 2: error: macro A redefined
154 1: note: location of previous definition
155 ''')
156
157 check_macro_eval('''\
158 #define A A
159 #define B 1
160 ''', {
161     'A': None,
162     'B': 1,
163 }, '''\
164 1: error: macro definition A refers to itself
165 ''')
166
167 check_macro_eval('''\
168 #define A B
169 #define B A
170 ''', {
171     'A': None,
172     'B': None,
173 }, '''\
174 1: error: macro definition A refers to itself
175 2: note: evaluated from B
176 ''')
177
178 check_macro_eval('''\
179 #define A B
180 #define B C
181 #define C A
182 ''', {
183     'A': None,
184     'B': None,
185     'C': None,
186 }, '''\
187 1: error: macro definition A refers to itself
188 3: note: evaluated from C
189 2: note: evaluated from B
190 ''')
191
192 check_macro_eval('''\
193 #define A 1 +
194 ''', {
195     'A': None,
196 }, '''\
197 1: error: uninterpretable macro token sequence: 1 +
198 ''')
199
200 check_macro_eval('''\
201 #define A 3*5
202 ''', {
203     'A': None,
204 }, '''\
205 1: error: uninterpretable macro token sequence: 3 * 5
206 ''')
207
208 check_macro_eval('''\
209 #define A 3 + 5
210 ''', {
211     'A': 8,
212 }, '''\
213 1: error: missing parentheses around + expression
214 1: note: in definition of macro A
215 ''')
216
217 if errors:
218     sys.exit(1)