@@ -117,3 +117,274 @@ fn multiple_files_in_different_locations_with_debug_info() {
117
117
//The functions are defined correctly
118
118
filtered_assert_snapshot ! ( results. join( "\n " ) ) ;
119
119
}
120
+
121
+ #[ test]
122
+ fn forward_declared_constant_is_also_marked_constant ( ) {
123
+ // GIVEN 2 sources, one with a forward declaration of a constant
124
+ // and the other with the definition of that constant.
125
+ let src1 = SourceCode :: new (
126
+ "
127
+ FUNCTION main : INT
128
+ VAR
129
+ f: foo;
130
+ END_VAR
131
+ mainProg(f.something_to_initialize);
132
+ END_FUNCTION
133
+
134
+ " ,
135
+ "external_file1.st" ,
136
+ ) ;
137
+ let src2 = SourceCode :: new (
138
+ "
139
+ VAR_GLOBAL CONSTANT
140
+ a: INT := 10;
141
+ END_VAR
142
+
143
+ PROGRAM mainProg
144
+ VAR_INPUT
145
+ a: INT;
146
+ END_VAR
147
+ END_PROGRAM
148
+
149
+ FUNCTION_BLOCK foo
150
+ VAR
151
+ something_to_initialize: INT := 10 + a;
152
+ END_VAR
153
+ END_FUNCTION_BLOCK
154
+ " ,
155
+ "external_file2.st" ,
156
+ ) ;
157
+
158
+ // WHEN they are generated
159
+ let results = compile_with_root ( vec ! [ src1, src2] , vec ! [ ] , "root" , DebugLevel :: Full ( 5 ) ) . unwrap ( ) ;
160
+
161
+ // THEN the constant is marked as constant in the generated code
162
+ filtered_assert_snapshot ! ( results. join( "\n " ) , @r###"
163
+ ; ModuleID = 'external_file1.st'
164
+ source_filename = "external_file1.st"
165
+ target datalayout = "[filtered]"
166
+ target triple = "[filtered]"
167
+
168
+ %foo = type { i16 }
169
+ %mainProg = type { i16 }
170
+
171
+ @__foo__init = external unnamed_addr constant %foo, !dbg !0
172
+ @mainProg_instance = external global %mainProg, !dbg !8
173
+
174
+ define i16 @main() !dbg !18 {
175
+ entry:
176
+ %main = alloca i16, align 2
177
+ %f = alloca %foo, align 8
178
+ call void @llvm.dbg.declare(metadata %foo* %f, metadata !23, metadata !DIExpression()), !dbg !24
179
+ %0 = bitcast %foo* %f to i8*
180
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %0, i8* align 1 bitcast (%foo* @__foo__init to i8*), i64 ptrtoint (%foo* getelementptr (%foo, %foo* null, i32 1) to i64), i1 false)
181
+ call void @llvm.dbg.declare(metadata i16* %main, metadata !25, metadata !DIExpression()), !dbg !26
182
+ store i16 0, i16* %main, align 2
183
+ call void @__init_foo(%foo* %f), !dbg !27
184
+ call void @__user_init_foo(%foo* %f), !dbg !27
185
+ %something_to_initialize = getelementptr inbounds %foo, %foo* %f, i32 0, i32 0, !dbg !27
186
+ %load_something_to_initialize = load i16, i16* %something_to_initialize, align 2, !dbg !27
187
+ store i16 %load_something_to_initialize, i16* getelementptr inbounds (%mainProg, %mainProg* @mainProg_instance, i32 0, i32 0), align 2, !dbg !27
188
+ call void @mainProg(%mainProg* @mainProg_instance), !dbg !28
189
+ %main_ret = load i16, i16* %main, align 2, !dbg !29
190
+ ret i16 %main_ret, !dbg !29
191
+ }
192
+
193
+ declare !dbg !30 void @foo(%foo*)
194
+
195
+ declare void @__init_foo(%foo*)
196
+
197
+ declare !dbg !33 void @__user_init_foo(%foo*)
198
+
199
+ declare !dbg !38 void @mainProg(%mainProg*)
200
+
201
+ ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
202
+ declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
203
+
204
+ ; Function Attrs: argmemonly nofree nounwind willreturn
205
+ declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #1
206
+
207
+ attributes #0 = { nofree nosync nounwind readnone speculatable willreturn }
208
+ attributes #1 = { argmemonly nofree nounwind willreturn }
209
+
210
+ !llvm.module.flags = !{!13, !14}
211
+ !llvm.dbg.cu = !{!15}
212
+
213
+ !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
214
+ !1 = distinct !DIGlobalVariable(name: "__foo__init", scope: !2, file: !2, line: 12, type: !3, isLocal: false, isDefinition: true)
215
+ !2 = !DIFile(filename: "external_file2.st", directory: "")
216
+ !3 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !4)
217
+ !4 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", scope: !2, file: !2, line: 12, size: 16, align: 64, flags: DIFlagPublic, elements: !5, identifier: "foo")
218
+ !5 = !{!6}
219
+ !6 = !DIDerivedType(tag: DW_TAG_member, name: "something_to_initialize", scope: !2, file: !2, line: 14, baseType: !7, size: 16, align: 16, flags: DIFlagPublic)
220
+ !7 = !DIBasicType(name: "INT", size: 16, encoding: DW_ATE_signed, flags: DIFlagPublic)
221
+ !8 = !DIGlobalVariableExpression(var: !9, expr: !DIExpression())
222
+ !9 = distinct !DIGlobalVariable(name: "mainProg", scope: !2, file: !2, line: 6, type: !10, isLocal: false, isDefinition: true)
223
+ !10 = !DICompositeType(tag: DW_TAG_structure_type, name: "mainProg", scope: !2, file: !2, line: 6, size: 16, align: 64, flags: DIFlagPublic, elements: !11, identifier: "mainProg")
224
+ !11 = !{!12}
225
+ !12 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !2, file: !2, line: 8, baseType: !7, size: 16, align: 16, flags: DIFlagPublic)
226
+ !13 = !{i32 2, !"Dwarf Version", i32 5}
227
+ !14 = !{i32 2, !"Debug Info Version", i32 3}
228
+ !15 = distinct !DICompileUnit(language: DW_LANG_C, file: !16, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !17, splitDebugInlining: false)
229
+ !16 = !DIFile(filename: "external_file1.st", directory: "root")
230
+ !17 = !{!0, !8}
231
+ !18 = distinct !DISubprogram(name: "main", linkageName: "main", scope: !19, file: !19, line: 2, type: !20, scopeLine: 2, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !15, retainedNodes: !22)
232
+ !19 = !DIFile(filename: "external_file1.st", directory: "")
233
+ !20 = !DISubroutineType(flags: DIFlagPublic, types: !21)
234
+ !21 = !{null}
235
+ !22 = !{}
236
+ !23 = !DILocalVariable(name: "f", scope: !18, file: !19, line: 4, type: !4, align: 64)
237
+ !24 = !DILocation(line: 4, column: 8, scope: !18)
238
+ !25 = !DILocalVariable(name: "main", scope: !18, file: !19, line: 2, type: !7, align: 16)
239
+ !26 = !DILocation(line: 2, column: 13, scope: !18)
240
+ !27 = !DILocation(line: 0, scope: !18)
241
+ !28 = !DILocation(line: 6, column: 8, scope: !18)
242
+ !29 = !DILocation(line: 7, column: 4, scope: !18)
243
+ !30 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: !2, file: !2, line: 12, type: !31, scopeLine: 16, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !15, retainedNodes: !22)
244
+ !31 = !DISubroutineType(flags: DIFlagPublic, types: !32)
245
+ !32 = !{null, !4}
246
+ !33 = distinct !DISubprogram(name: "__user_init_foo", linkageName: "__user_init_foo", scope: !34, file: !34, type: !35, scopeLine: 1, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !15, retainedNodes: !22)
247
+ !34 = !DIFile(filename: "__initializers", directory: "")
248
+ !35 = !DISubroutineType(flags: DIFlagPublic, types: !36)
249
+ !36 = !{null, !37}
250
+ !37 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__auto_pointer_to_foo", baseType: !4, size: 64, align: 64, dwarfAddressSpace: 1)
251
+ !38 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 6, type: !39, scopeLine: 10, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !15, retainedNodes: !22)
252
+ !39 = !DISubroutineType(flags: DIFlagPublic, types: !40)
253
+ !40 = !{null, !10, !7}
254
+
255
+ ; ModuleID = 'external_file2.st'
256
+ source_filename = "external_file2.st"
257
+ target datalayout = "[filtered]"
258
+ target triple = "[filtered]"
259
+
260
+ %mainProg = type { i16 }
261
+ %foo = type { i16 }
262
+
263
+ @a = unnamed_addr constant i16 10, !dbg !0
264
+ @mainProg_instance = global %mainProg zeroinitializer, !dbg !5
265
+ @__foo__init = unnamed_addr constant %foo { i16 20 }, !dbg !10
266
+
267
+ define void @mainProg(%mainProg* %0) !dbg !21 {
268
+ entry:
269
+ call void @llvm.dbg.declare(metadata %mainProg* %0, metadata !25, metadata !DIExpression()), !dbg !26
270
+ %a = getelementptr inbounds %mainProg, %mainProg* %0, i32 0, i32 0
271
+ ret void, !dbg !26
272
+ }
273
+
274
+ define void @foo(%foo* %0) !dbg !27 {
275
+ entry:
276
+ call void @llvm.dbg.declare(metadata %foo* %0, metadata !30, metadata !DIExpression()), !dbg !31
277
+ %this = alloca %foo*, align 8
278
+ store %foo* %0, %foo** %this, align 8
279
+ %something_to_initialize = getelementptr inbounds %foo, %foo* %0, i32 0, i32 0
280
+ ret void, !dbg !31
281
+ }
282
+
283
+ ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
284
+ declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
285
+
286
+ attributes #0 = { nofree nosync nounwind readnone speculatable willreturn }
287
+
288
+ !llvm.module.flags = !{!16, !17}
289
+ !llvm.dbg.cu = !{!18}
290
+
291
+ !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
292
+ !1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !2, line: 3, type: !3, isLocal: false, isDefinition: true)
293
+ !2 = !DIFile(filename: "external_file2.st", directory: "")
294
+ !3 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !4)
295
+ !4 = !DIBasicType(name: "INT", size: 16, encoding: DW_ATE_signed, flags: DIFlagPublic)
296
+ !5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
297
+ !6 = distinct !DIGlobalVariable(name: "mainProg", scope: !2, file: !2, line: 6, type: !7, isLocal: false, isDefinition: true)
298
+ !7 = !DICompositeType(tag: DW_TAG_structure_type, name: "mainProg", scope: !2, file: !2, line: 6, size: 16, align: 64, flags: DIFlagPublic, elements: !8, identifier: "mainProg")
299
+ !8 = !{!9}
300
+ !9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !2, file: !2, line: 8, baseType: !4, size: 16, align: 16, flags: DIFlagPublic)
301
+ !10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression())
302
+ !11 = distinct !DIGlobalVariable(name: "__foo__init", scope: !2, file: !2, line: 12, type: !12, isLocal: false, isDefinition: true)
303
+ !12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13)
304
+ !13 = !DICompositeType(tag: DW_TAG_structure_type, name: "foo", scope: !2, file: !2, line: 12, size: 16, align: 64, flags: DIFlagPublic, elements: !14, identifier: "foo")
305
+ !14 = !{!15}
306
+ !15 = !DIDerivedType(tag: DW_TAG_member, name: "something_to_initialize", scope: !2, file: !2, line: 14, baseType: !4, size: 16, align: 16, flags: DIFlagPublic)
307
+ !16 = !{i32 2, !"Dwarf Version", i32 5}
308
+ !17 = !{i32 2, !"Debug Info Version", i32 3}
309
+ !18 = distinct !DICompileUnit(language: DW_LANG_C, file: !19, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !20, splitDebugInlining: false)
310
+ !19 = !DIFile(filename: "external_file2.st", directory: "root")
311
+ !20 = !{!0, !5, !10}
312
+ !21 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 6, type: !22, scopeLine: 10, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !18, retainedNodes: !24)
313
+ !22 = !DISubroutineType(flags: DIFlagPublic, types: !23)
314
+ !23 = !{null, !7, !4}
315
+ !24 = !{}
316
+ !25 = !DILocalVariable(name: "mainProg", scope: !21, file: !2, line: 10, type: !7)
317
+ !26 = !DILocation(line: 10, column: 4, scope: !21)
318
+ !27 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: !2, file: !2, line: 12, type: !28, scopeLine: 16, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !18, retainedNodes: !24)
319
+ !28 = !DISubroutineType(flags: DIFlagPublic, types: !29)
320
+ !29 = !{null, !13}
321
+ !30 = !DILocalVariable(name: "foo", scope: !27, file: !2, line: 16, type: !13)
322
+ !31 = !DILocation(line: 16, column: 4, scope: !27)
323
+
324
+ ; ModuleID = '__initializers'
325
+ source_filename = "__initializers"
326
+ target datalayout = "[filtered]"
327
+ target triple = "[filtered]"
328
+
329
+ %mainProg = type { i16 }
330
+ %foo = type { i16 }
331
+
332
+ @mainProg_instance = external global %mainProg
333
+ @__foo__init = external unnamed_addr constant %foo
334
+
335
+ define void @__init_mainprog(%mainProg* %0) {
336
+ entry:
337
+ %self = alloca %mainProg*, align 8
338
+ store %mainProg* %0, %mainProg** %self, align 8
339
+ ret void
340
+ }
341
+
342
+ declare void @mainProg(%mainProg*)
343
+
344
+ define void @__init_foo(%foo* %0) {
345
+ entry:
346
+ %self = alloca %foo*, align 8
347
+ store %foo* %0, %foo** %self, align 8
348
+ ret void
349
+ }
350
+
351
+ declare void @foo(%foo*)
352
+
353
+ define void @__user_init_mainProg(%mainProg* %0) {
354
+ entry:
355
+ %self = alloca %mainProg*, align 8
356
+ store %mainProg* %0, %mainProg** %self, align 8
357
+ ret void
358
+ }
359
+
360
+ define void @__user_init_foo(%foo* %0) {
361
+ entry:
362
+ %self = alloca %foo*, align 8
363
+ store %foo* %0, %foo** %self, align 8
364
+ ret void
365
+ }
366
+
367
+ ; ModuleID = '__init___TestProject'
368
+ source_filename = "__init___TestProject"
369
+ target datalayout = "[filtered]"
370
+ target triple = "[filtered]"
371
+
372
+ %mainProg = type { i16 }
373
+
374
+ @mainProg_instance = external global %mainProg
375
+ @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___TestProject, i8* null }]
376
+
377
+ define void @__init___TestProject() {
378
+ entry:
379
+ call void @__init_mainprog(%mainProg* @mainProg_instance)
380
+ call void @__user_init_mainProg(%mainProg* @mainProg_instance)
381
+ ret void
382
+ }
383
+
384
+ declare void @__init_mainprog(%mainProg*)
385
+
386
+ declare void @mainProg(%mainProg*)
387
+
388
+ declare void @__user_init_mainProg(%mainProg*)
389
+ "### ) ;
390
+ }
0 commit comments