Internally these would treat the cast same as a normal conversion from int[7] to int[], which allows code at CTFE to erroneously succeed where it would raise a SEGV at run-time.
1 |
/**
|
|
2 |
* Defines declarations of various attributes.
|
|
3 |
*
|
|
4 |
* The term 'attribute' refers to things that can apply to a larger scope than a single declaration.
|
|
5 |
* Among them are:
|
|
6 |
* - Alignment (`align(8)`)
|
|
7 |
* - User defined attributes (`@UDA`)
|
|
8 |
* - Function Attributes (`@safe`)
|
|
9 |
* - Storage classes (`static`, `__gshared`)
|
|
10 |
* - Mixin declarations (`mixin("int x;")`)
|
|
11 |
* - Conditional compilation (`static if`, `static foreach`)
|
|
12 |
* - Linkage (`extern(C)`)
|
|
13 |
* - Anonymous structs / unions
|
|
14 |
* - Protection (`private`, `public`)
|
|
15 |
* - Deprecated declarations (`@deprecated`)
|
|
16 |
*
|
|
17 |
* Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
|
|
18 |
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
|
19 |
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
|
20 |
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d)
|
|
21 |
* Documentation: https://dlang.org/phobos/dmd_attrib.html
|
|
22 |
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/attrib.d
|
|
23 |
*/
|
|
24 |
|
|
25 |
module dmd.attrib; |
|
26 |
|
|
27 |
import dmd.aggregate; |
|
28 |
import dmd.arraytypes; |
|
29 |
import dmd.cond; |
|
30 |
import dmd.declaration; |
|
31 |
import dmd.dmodule; |
|
32 |
import dmd.dscope; |
|
33 |
import dmd.dsymbol; |
|
34 |
import dmd.dsymbolsem : dsymbolSemantic; |
|
35 |
import dmd.expression; |
|
36 |
import dmd.expressionsem : arrayExpressionSemantic; |
|
37 |
import dmd.func; |
|
38 |
import dmd.globals; |
|
39 |
import dmd.hdrgen : protectionToBuffer; |
|
40 |
import dmd.id; |
|
41 |
import dmd.identifier; |
|
42 |
import dmd.mtype; |
|
43 |
import dmd.objc; // for objc.addSymbols |
|
44 |
import dmd.root.outbuffer; |
|
45 |
import dmd.target; // for target.systemLinkage |
|
46 |
import dmd.tokens; |
|
47 |
import dmd.visitor; |
|
48 |
|
|
49 |
/***********************************************************
|
|
50 |
* Abstract attribute applied to Dsymbol's used as a common
|
|
51 |
* ancestor for storage classes (StorageClassDeclaration),
|
|
52 |
* linkage (LinkageDeclaration) and others.
|
|
53 |
*/
|
|
54 |
extern (C++) abstract class AttribDeclaration : Dsymbol |
|
55 |
{
|
|
56 |
Dsymbols* decl; /// Dsymbol's affected by this AttribDeclaration |
|
57 |
|
|
58 | 1 |
extern (D) this(Dsymbols* decl) |
59 |
{
|
|
60 | 1 |
this.decl = decl; |
61 |
}
|
|
62 |
|
|
63 | 1 |
extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl) |
64 |
{
|
|
65 | 1 |
super(loc, ident); |
66 | 1 |
this.decl = decl; |
67 |
}
|
|
68 |
|
|
69 |
Dsymbols* include(Scope* sc) |
|
70 |
{
|
|
71 | 1 |
if (errors) |
72 | 1 |
return null; |
73 |
|
|
74 | 1 |
return decl; |
75 |
}
|
|
76 |
|
|
77 |
/****************************************
|
|
78 |
* Create a new scope if one or more given attributes
|
|
79 |
* are different from the sc's.
|
|
80 |
* If the returned scope != sc, the caller should pop
|
|
81 |
* the scope after it used.
|
|
82 |
*/
|
|
83 |
extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage, |
|
84 |
CPPMANGLE cppmangle, Prot protection, int explicitProtection, |
|
85 |
AlignDeclaration aligndecl, PINLINE inlining) |
|
86 |
{
|
|
87 | 1 |
Scope* sc2 = sc; |
88 | 1 |
if (stc != sc.stc || |
89 | 1 |
linkage != sc.linkage || |
90 | 1 |
cppmangle != sc.cppmangle || |
91 | 1 |
!protection.isSubsetOf(sc.protection) || |
92 | 1 |
explicitProtection != sc.explicitProtection || |
93 | 1 |
aligndecl !is sc.aligndecl || |
94 | 1 |
inlining != sc.inlining) |
95 |
{
|
|
96 |
// create new one for changes
|
|
97 | 1 |
sc2 = sc.copy(); |
98 | 1 |
sc2.stc = stc; |
99 | 1 |
sc2.linkage = linkage; |
100 | 1 |
sc2.cppmangle = cppmangle; |
101 | 1 |
sc2.protection = protection; |
102 | 1 |
sc2.explicitProtection = explicitProtection; |
103 | 1 |
sc2.aligndecl = aligndecl; |
104 | 1 |
sc2.inlining = inlining; |
105 |
}
|
|
106 | 1 |
return sc2; |
107 |
}
|
|
108 |
|
|
109 |
/****************************************
|
|
110 |
* A hook point to supply scope for members.
|
|
111 |
* addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
|
|
112 |
*/
|
|
113 |
Scope* newScope(Scope* sc) |
|
114 |
{
|
|
115 | 1 |
return sc; |
116 |
}
|
|
117 |
|
|
118 |
override void addMember(Scope* sc, ScopeDsymbol sds) |
|
119 |
{
|
|
120 | 1 |
Dsymbols* d = include(sc); |
121 | 1 |
if (d) |
122 |
{
|
|
123 | 1 |
Scope* sc2 = newScope(sc); |
124 | 1 |
d.foreachDsymbol( s => s.addMember(sc2, sds) ); |
125 | 1 |
if (sc2 != sc) |
126 | 1 |
sc2.pop(); |
127 |
}
|
|
128 |
}
|
|
129 |
|
|
130 |
override void setScope(Scope* sc) |
|
131 |
{
|
|
132 | 1 |
Dsymbols* d = include(sc); |
133 |
//printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
|
|
134 | 1 |
if (d) |
135 |
{
|
|
136 | 1 |
Scope* sc2 = newScope(sc); |
137 | 1 |
d.foreachDsymbol( s => s.setScope(sc2) ); |
138 | 1 |
if (sc2 != sc) |
139 | 1 |
sc2.pop(); |
140 |
}
|
|
141 |
}
|
|
142 |
|
|
143 |
override void importAll(Scope* sc) |
|
144 |
{
|
|
145 | 1 |
Dsymbols* d = include(sc); |
146 |
//printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
|
|
147 | 1 |
if (d) |
148 |
{
|
|
149 | 1 |
Scope* sc2 = newScope(sc); |
150 | 1 |
d.foreachDsymbol( s => s.importAll(sc2) ); |
151 | 1 |
if (sc2 != sc) |
152 | 1 |
sc2.pop(); |
153 |
}
|
|
154 |
}
|
|
155 |
|
|
156 |
override void addComment(const(char)* comment) |
|
157 |
{
|
|
158 |
//printf("AttribDeclaration::addComment %s\n", comment);
|
|
159 | 1 |
if (comment) |
160 |
{
|
|
161 | 1 |
include(null).foreachDsymbol( s => s.addComment(comment) ); |
162 |
}
|
|
163 |
}
|
|
164 |
|
|
165 |
override const(char)* kind() const |
|
166 |
{
|
|
167 |
return "attribute"; |
|
168 |
}
|
|
169 |
|
|
170 |
override bool oneMember(Dsymbol* ps, Identifier ident) |
|
171 |
{
|
|
172 | 1 |
Dsymbols* d = include(null); |
173 | 1 |
return Dsymbol.oneMembers(d, ps, ident); |
174 |
}
|
|
175 |
|
|
176 |
override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) |
|
177 |
{
|
|
178 | 1 |
include(null).foreachDsymbol( s => s.setFieldOffset(ad, poffset, isunion) ); |
179 |
}
|
|
180 |
|
|
181 |
override final bool hasPointers() |
|
182 |
{
|
|
183 | 1 |
return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; |
184 |
}
|
|
185 |
|
|
186 |
override final bool hasStaticCtorOrDtor() |
|
187 |
{
|
|
188 | 1 |
return include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0; |
189 |
}
|
|
190 |
|
|
191 |
override final void checkCtorConstInit() |
|
192 |
{
|
|
193 | 1 |
include(null).foreachDsymbol( s => s.checkCtorConstInit() ); |
194 |
}
|
|
195 |
|
|
196 |
/****************************************
|
|
197 |
*/
|
|
198 |
override final void addLocalClass(ClassDeclarations* aclasses) |
|
199 |
{
|
|
200 | 1 |
include(null).foreachDsymbol( s => s.addLocalClass(aclasses) ); |
201 |
}
|
|
202 |
|
|
203 |
override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories) |
|
204 |
{
|
|
205 |
objc.addSymbols(this, classes, categories); |
|
206 |
}
|
|
207 |
|
|
208 |
override final inout(AttribDeclaration) isAttribDeclaration() inout |
|
209 |
{
|
|
210 | 1 |
return this; |
211 |
}
|
|
212 |
|
|
213 |
override void accept(Visitor v) |
|
214 |
{
|
|
215 |
v.visit(this); |
|
216 |
}
|
|
217 |
}
|
|
218 |
|
|
219 |
/***********************************************************
|
|
220 |
* Storage classes applied to Dsymbols, e.g. `const int i;`
|
|
221 |
*
|
|
222 |
* <stc> <decl...>
|
|
223 |
*/
|
|
224 |
extern (C++) class StorageClassDeclaration : AttribDeclaration |
|
225 |
{
|
|
226 |
StorageClass stc; |
|
227 |
|
|
228 | 1 |
extern (D) this(StorageClass stc, Dsymbols* decl) |
229 |
{
|
|
230 | 1 |
super(decl); |
231 | 1 |
this.stc = stc; |
232 |
}
|
|
233 |
|
|
234 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
235 |
{
|
|
236 | 1 |
assert(!s); |
237 | 1 |
return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl)); |
238 |
}
|
|
239 |
|
|
240 |
override Scope* newScope(Scope* sc) |
|
241 |
{
|
|
242 | 1 |
StorageClass scstc = sc.stc; |
243 |
/* These sets of storage classes are mutually exclusive,
|
|
244 |
* so choose the innermost or most recent one.
|
|
245 |
*/
|
|
246 | 1 |
if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest)) |
247 | 1 |
scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest); |
248 | 1 |
if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared)) |
249 | 1 |
scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared); |
250 | 1 |
if (stc & (STC.const_ | STC.immutable_ | STC.manifest)) |
251 | 1 |
scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest); |
252 | 1 |
if (stc & (STC.gshared | STC.shared_ | STC.tls)) |
253 | 1 |
scstc &= ~(STC.gshared | STC.shared_ | STC.tls); |
254 | 1 |
if (stc & (STC.safe | STC.trusted | STC.system)) |
255 | 1 |
scstc &= ~(STC.safe | STC.trusted | STC.system); |
256 | 1 |
scstc |= stc; |
257 |
//printf("scstc = x%llx\n", scstc);
|
|
258 | 1 |
return createNewScope(sc, scstc, sc.linkage, sc.cppmangle, |
259 |
sc.protection, sc.explicitProtection, sc.aligndecl, sc.inlining); |
|
260 |
}
|
|
261 |
|
|
262 |
override final bool oneMember(Dsymbol* ps, Identifier ident) |
|
263 |
{
|
|
264 | 1 |
bool t = Dsymbol.oneMembers(decl, ps, ident); |
265 | 1 |
if (t && *ps) |
266 |
{
|
|
267 |
/* This is to deal with the following case:
|
|
268 |
* struct Tick {
|
|
269 |
* template to(T) { const T to() { ... } }
|
|
270 |
* }
|
|
271 |
* For eponymous function templates, the 'const' needs to get attached to 'to'
|
|
272 |
* before the semantic analysis of 'to', so that template overloading based on the
|
|
273 |
* 'this' pointer can be successful.
|
|
274 |
*/
|
|
275 | 1 |
FuncDeclaration fd = (*ps).isFuncDeclaration(); |
276 | 1 |
if (fd) |
277 |
{
|
|
278 |
/* Use storage_class2 instead of storage_class otherwise when we do .di generation
|
|
279 |
* we'll wind up with 'const const' rather than 'const'.
|
|
280 |
*/
|
|
281 |
/* Don't think we need to worry about mutually exclusive storage classes here
|
|
282 |
*/
|
|
283 | 1 |
fd.storage_class2 |= stc; |
284 |
}
|
|
285 |
}
|
|
286 | 1 |
return t; |
287 |
}
|
|
288 |
|
|
289 |
override void addMember(Scope* sc, ScopeDsymbol sds) |
|
290 |
{
|
|
291 | 1 |
Dsymbols* d = include(sc); |
292 | 1 |
if (d) |
293 |
{
|
|
294 | 1 |
Scope* sc2 = newScope(sc); |
295 |
|
|
296 | 1 |
d.foreachDsymbol( (s) |
297 |
{
|
|
298 |
//printf("\taddMember %s to %s\n", s.toChars(), sds.toChars());
|
|
299 |
// STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol)
|
|
300 | 1 |
if (auto decl = s.isDeclaration()) |
301 |
{
|
|
302 | 1 |
decl.storage_class |= stc & STC.local; |
303 | 1 |
if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case? |
304 |
{
|
|
305 |
sdecl.stc |= stc & STC.local; |
|
306 |
}
|
|
307 |
}
|
|
308 | 1 |
s.addMember(sc2, sds); |
309 |
});
|
|
310 |
|
|
311 | 1 |
if (sc2 != sc) |
312 | 1 |
sc2.pop(); |
313 |
}
|
|
314 |
|
|
315 |
}
|
|
316 |
|
|
317 |
override inout(StorageClassDeclaration) isStorageClassDeclaration() inout |
|
318 |
{
|
|
319 |
return this; |
|
320 |
}
|
|
321 |
|
|
322 |
override void accept(Visitor v) |
|
323 |
{
|
|
324 | 1 |
v.visit(this); |
325 |
}
|
|
326 |
}
|
|
327 |
|
|
328 |
/***********************************************************
|
|
329 |
* Deprecation with an additional message applied to Dsymbols,
|
|
330 |
* e.g. `deprecated("Superseeded by foo") int bar;`.
|
|
331 |
* (Note that `deprecated int bar;` is currently represented as a
|
|
332 |
* StorageClassDeclaration with STC.deprecated_)
|
|
333 |
*
|
|
334 |
* `deprecated(<msg>) <decl...>`
|
|
335 |
*/
|
|
336 |
extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration |
|
337 |
{
|
|
338 |
Expression msg; /// deprecation message |
|
339 |
const(char)* msgstr; /// cached string representation of msg |
|
340 |
|
|
341 | 1 |
extern (D) this(Expression msg, Dsymbols* decl) |
342 |
{
|
|
343 | 1 |
super(STC.deprecated_, decl); |
344 | 1 |
this.msg = msg; |
345 |
}
|
|
346 |
|
|
347 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
348 |
{
|
|
349 | 1 |
assert(!s); |
350 | 1 |
return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl)); |
351 |
}
|
|
352 |
|
|
353 |
/**
|
|
354 |
* Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
|
|
355 |
*
|
|
356 |
* Calls `StorageClassDeclaration.newScope` (as it must be called or copied
|
|
357 |
* in any function overriding `newScope`), then set the `Scope`'s depdecl.
|
|
358 |
*
|
|
359 |
* Returns:
|
|
360 |
* Always a new scope, to use for this `DeprecatedDeclaration`'s members.
|
|
361 |
*/
|
|
362 |
override Scope* newScope(Scope* sc) |
|
363 |
{
|
|
364 | 1 |
auto scx = super.newScope(sc); |
365 |
// The enclosing scope is deprecated as well
|
|
366 | 1 |
if (scx == sc) |
367 | 1 |
scx = sc.push(); |
368 | 1 |
scx.depdecl = this; |
369 | 1 |
return scx; |
370 |
}
|
|
371 |
|
|
372 |
override void setScope(Scope* sc) |
|
373 |
{
|
|
374 |
//printf("DeprecatedDeclaration::setScope() %p\n", this);
|
|
375 | 1 |
if (decl) |
376 | 1 |
Dsymbol.setScope(sc); // for forward reference |
377 | 1 |
return AttribDeclaration.setScope(sc); |
378 |
}
|
|
379 |
|
|
380 |
override void accept(Visitor v) |
|
381 |
{
|
|
382 | 1 |
v.visit(this); |
383 |
}
|
|
384 |
}
|
|
385 |
|
|
386 |
/***********************************************************
|
|
387 |
* Linkage attribute applied to Dsymbols, e.g.
|
|
388 |
* `extern(C) void foo()`.
|
|
389 |
*
|
|
390 |
* `extern(<linkage>) <decl...>`
|
|
391 |
*/
|
|
392 |
extern (C++) final class LinkDeclaration : AttribDeclaration |
|
393 |
{
|
|
394 |
LINK linkage; /// either explicitly set or `default_` |
|
395 |
|
|
396 | 1 |
extern (D) this(LINK linkage, Dsymbols* decl) |
397 |
{
|
|
398 | 1 |
super(decl); |
399 |
//printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
|
|
400 | 1 |
this.linkage = (linkage == LINK.system) ? target.systemLinkage() : linkage; |
401 |
}
|
|
402 |
|
|
403 |
static LinkDeclaration create(LINK p, Dsymbols* decl) |
|
404 |
{
|
|
405 |
return new LinkDeclaration(p, decl); |
|
406 |
}
|
|
407 |
|
|
408 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
409 |
{
|
|
410 | 1 |
assert(!s); |
411 | 1 |
return new LinkDeclaration(linkage, Dsymbol.arraySyntaxCopy(decl)); |
412 |
}
|
|
413 |
|
|
414 |
override Scope* newScope(Scope* sc) |
|
415 |
{
|
|
416 | 1 |
return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, |
417 |
sc.aligndecl, sc.inlining); |
|
418 |
}
|
|
419 |
|
|
420 |
override const(char)* toChars() const |
|
421 |
{
|
|
422 | 1 |
return toString().ptr; |
423 |
}
|
|
424 |
|
|
425 |
extern(D) override const(char)[] toString() const |
|
426 |
{
|
|
427 | 1 |
return "extern ()"; |
428 |
}
|
|
429 |
|
|
430 |
override void accept(Visitor v) |
|
431 |
{
|
|
432 | 1 |
v.visit(this); |
433 |
}
|
|
434 |
}
|
|
435 |
|
|
436 |
/***********************************************************
|
|
437 |
* Attribute declaring whether an external aggregate should be mangled as
|
|
438 |
* a struct or class in C++, e.g. `extern(C++, struct) class C { ... }`.
|
|
439 |
* This is required for correct name mangling on MSVC targets,
|
|
440 |
* see cppmanglewin.d for details.
|
|
441 |
*
|
|
442 |
* `extern(C++, <cppmangle>) <decl...>`
|
|
443 |
*/
|
|
444 |
extern (C++) final class CPPMangleDeclaration : AttribDeclaration |
|
445 |
{
|
|
446 |
CPPMANGLE cppmangle; |
|
447 |
|
|
448 | 1 |
extern (D) this(CPPMANGLE cppmangle, Dsymbols* decl) |
449 |
{
|
|
450 | 1 |
super(decl); |
451 |
//printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl);
|
|
452 | 1 |
this.cppmangle = cppmangle; |
453 |
}
|
|
454 |
|
|
455 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
456 |
{
|
|
457 |
assert(!s); |
|
458 |
return new CPPMangleDeclaration(cppmangle, Dsymbol.arraySyntaxCopy(decl)); |
|
459 |
}
|
|
460 |
|
|
461 |
override Scope* newScope(Scope* sc) |
|
462 |
{
|
|
463 | 1 |
return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.protection, sc.explicitProtection, |
464 |
sc.aligndecl, sc.inlining); |
|
465 |
}
|
|
466 |
|
|
467 |
override void setScope(Scope* sc) |
|
468 |
{
|
|
469 | 1 |
if (decl) |
470 | 1 |
Dsymbol.setScope(sc); // for forward reference |
471 | 1 |
return AttribDeclaration.setScope(sc); |
472 |
}
|
|
473 |
|
|
474 |
override const(char)* toChars() const |
|
475 |
{
|
|
476 |
return toString().ptr; |
|
477 |
}
|
|
478 |
|
|
479 |
extern(D) override const(char)[] toString() const |
|
480 |
{
|
|
481 |
return "extern ()"; |
|
482 |
}
|
|
483 |
|
|
484 |
override void accept(Visitor v) |
|
485 |
{
|
|
486 | 1 |
v.visit(this); |
487 |
}
|
|
488 |
}
|
|
489 |
|
|
490 |
/**
|
|
491 |
* A node to represent an `extern(C++)` namespace attribute
|
|
492 |
*
|
|
493 |
* There are two ways to declarate a symbol as member of a namespace:
|
|
494 |
* `Nspace` and `CPPNamespaceDeclaration`.
|
|
495 |
* The former creates a scope for the symbol, and inject them in the
|
|
496 |
* parent scope at the same time.
|
|
497 |
* The later, this class, has no semantic implications and is only
|
|
498 |
* used for mangling.
|
|
499 |
* Additionally, this class allows one to use reserved identifiers
|
|
500 |
* (D keywords) in the namespace.
|
|
501 |
*
|
|
502 |
* A `CPPNamespaceDeclaration` can be created from an `Identifier`
|
|
503 |
* (already resolved) or from an `Expression`, which is CTFE-ed
|
|
504 |
* and can be either a `TupleExp`, in which can additional
|
|
505 |
* `CPPNamespaceDeclaration` nodes are created, or a `StringExp`.
|
|
506 |
*
|
|
507 |
* Note that this class, like `Nspace`, matches only one identifier
|
|
508 |
* part of a namespace. For the namespace `"foo::bar"`,
|
|
509 |
* the will be a `CPPNamespaceDeclaration` with its `ident`
|
|
510 |
* set to `"bar"`, and its `namespace` field pointing to another
|
|
511 |
* `CPPNamespaceDeclaration` with its `ident` set to `"foo"`.
|
|
512 |
*/
|
|
513 |
extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration |
|
514 |
{
|
|
515 |
/// CTFE-able expression, resolving to `TupleExp` or `StringExp`
|
|
516 |
Expression exp; |
|
517 |
|
|
518 |
extern (D) this(Identifier ident, Dsymbols* decl) |
|
519 |
{
|
|
520 |
super(decl); |
|
521 |
this.ident = ident; |
|
522 |
}
|
|
523 |
|
|
524 | 1 |
extern (D) this(Expression exp, Dsymbols* decl) |
525 |
{
|
|
526 | 1 |
super(decl); |
527 | 1 |
this.exp = exp; |
528 |
}
|
|
529 |
|
|
530 |
extern (D) this(Identifier ident, Expression exp, Dsymbols* decl, |
|
531 |
CPPNamespaceDeclaration parent) |
|
532 |
{
|
|
533 |
super(decl); |
|
534 |
this.ident = ident; |
|
535 |
this.exp = exp; |
|
536 |
this.cppnamespace = parent; |
|
537 |
}
|
|
538 |
|
|
539 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
540 |
{
|
|
541 |
assert(!s); |
|
542 |
return new CPPNamespaceDeclaration( |
|
543 |
this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace); |
|
544 |
}
|
|
545 |
|
|
546 |
/**
|
|
547 |
* Returns:
|
|
548 |
* A copy of the parent scope, with `this` as `namespace` and C++ linkage
|
|
549 |
*/
|
|
550 |
override Scope* newScope(Scope* sc) |
|
551 |
{
|
|
552 | 1 |
auto scx = sc.copy(); |
553 | 1 |
scx.linkage = LINK.cpp; |
554 | 1 |
scx.namespace = this; |
555 | 1 |
return scx; |
556 |
}
|
|
557 |
|
|
558 |
override const(char)* toChars() const |
|
559 |
{
|
|
560 |
return toString().ptr; |
|
561 |
}
|
|
562 |
|
|
563 |
extern(D) override const(char)[] toString() const |
|
564 |
{
|
|
565 |
return "extern (C++, `namespace`)"; |
|
566 |
}
|
|
567 |
|
|
568 |
override void accept(Visitor v) |
|
569 |
{
|
|
570 | 1 |
v.visit(this); |
571 |
}
|
|
572 |
|
|
573 | 1 |
override inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return this; } |
574 |
}
|
|
575 |
|
|
576 |
/***********************************************************
|
|
577 |
* Visibility declaration for Dsymbols, e.g. `public int i;`
|
|
578 |
*
|
|
579 |
* `<protection> <decl...>` or
|
|
580 |
* `package(<pkg_identifiers>) <decl...>` if `pkg_identifiers !is null`
|
|
581 |
*/
|
|
582 |
extern (C++) final class ProtDeclaration : AttribDeclaration |
|
583 |
{
|
|
584 |
Prot protection; /// the visibility |
|
585 |
Identifiers* pkg_identifiers; /// identifiers for `package(foo.bar)` or null |
|
586 |
|
|
587 |
/**
|
|
588 |
* Params:
|
|
589 |
* loc = source location of attribute token
|
|
590 |
* protection = protection attribute data
|
|
591 |
* decl = declarations which are affected by this protection attribute
|
|
592 |
*/
|
|
593 | 1 |
extern (D) this(const ref Loc loc, Prot protection, Dsymbols* decl) |
594 |
{
|
|
595 | 1 |
super(loc, null, decl); |
596 | 1 |
this.protection = protection; |
597 |
//printf("decl = %p\n", decl);
|
|
598 |
}
|
|
599 |
|
|
600 |
/**
|
|
601 |
* Params:
|
|
602 |
* loc = source location of attribute token
|
|
603 |
* pkg_identifiers = list of identifiers for a qualified package name
|
|
604 |
* decl = declarations which are affected by this protection attribute
|
|
605 |
*/
|
|
606 | 1 |
extern (D) this(const ref Loc loc, Identifiers* pkg_identifiers, Dsymbols* decl) |
607 |
{
|
|
608 | 1 |
super(loc, null, decl); |
609 | 1 |
this.protection.kind = Prot.Kind.package_; |
610 | 1 |
this.pkg_identifiers = pkg_identifiers; |
611 | 1 |
if (pkg_identifiers !is null && pkg_identifiers.dim > 0) |
612 |
{
|
|
613 | 1 |
Dsymbol tmp; |
614 | 1 |
Package.resolve(pkg_identifiers, &tmp, null); |
615 | 1 |
protection.pkg = tmp ? tmp.isPackage() : null; |
616 |
}
|
|
617 |
}
|
|
618 |
|
|
619 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
620 |
{
|
|
621 | 1 |
assert(!s); |
622 | 1 |
if (protection.kind == Prot.Kind.package_) |
623 | 1 |
return new ProtDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl)); |
624 |
else
|
|
625 | 1 |
return new ProtDeclaration(this.loc, protection, Dsymbol.arraySyntaxCopy(decl)); |
626 |
}
|
|
627 |
|
|
628 |
override Scope* newScope(Scope* sc) |
|
629 |
{
|
|
630 | 1 |
if (pkg_identifiers) |
631 |
dsymbolSemantic(this, sc); |
|
632 | 1 |
return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.protection, 1, sc.aligndecl, sc.inlining); |
633 |
}
|
|
634 |
|
|
635 |
override void addMember(Scope* sc, ScopeDsymbol sds) |
|
636 |
{
|
|
637 | 1 |
if (pkg_identifiers) |
638 |
{
|
|
639 | 1 |
Dsymbol tmp; |
640 | 1 |
Package.resolve(pkg_identifiers, &tmp, null); |
641 | 1 |
protection.pkg = tmp ? tmp.isPackage() : null; |
642 | 1 |
pkg_identifiers = null; |
643 |
}
|
|
644 | 1 |
if (protection.kind == Prot.Kind.package_ && protection.pkg && sc._module) |
645 |
{
|
|
646 | 1 |
Module m = sc._module; |
647 |
|
|
648 |
// While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
|
|
649 |
// each package's .isModule() properites are equal.
|
|
650 |
//
|
|
651 |
// Properties generated from `package(foo)` i.e. protection.pkg have .isModule() == null.
|
|
652 |
// This breaks package declarations of the package in question if they are declared in
|
|
653 |
// the same package.d file, which _do_ have a module associated with them, and hence a non-null
|
|
654 |
// isModule()
|
|
655 | 1 |
if (!m.isPackage() || !protection.pkg.ident.equals(m.isPackage().ident)) |
656 |
{
|
|
657 | 1 |
Package pkg = m.parent ? m.parent.isPackage() : null; |
658 | 1 |
if (!pkg || !protection.pkg.isAncestorPackageOf(pkg)) |
659 | 1 |
error("does not bind to one of ancestor packages of module `%s`", m.toPrettyChars(true)); |
660 |
}
|
|
661 |
}
|
|
662 | 1 |
return AttribDeclaration.addMember(sc, sds); |
663 |
}
|
|
664 |
|
|
665 |
override const(char)* kind() const |
|
666 |
{
|
|
667 | 1 |
return "protection attribute"; |
668 |
}
|
|
669 |
|
|
670 |
override const(char)* toPrettyChars(bool) |
|
671 |
{
|
|
672 | 1 |
assert(protection.kind > Prot.Kind.undefined); |
673 | 1 |
OutBuffer buf; |
674 | 1 |
protectionToBuffer(&buf, protection); |
675 | 1 |
return buf.extractChars(); |
676 |
}
|
|
677 |
|
|
678 |
override inout(ProtDeclaration) isProtDeclaration() inout |
|
679 |
{
|
|
680 | 1 |
return this; |
681 |
}
|
|
682 |
|
|
683 |
override void accept(Visitor v) |
|
684 |
{
|
|
685 | 1 |
v.visit(this); |
686 |
}
|
|
687 |
}
|
|
688 |
|
|
689 |
/***********************************************************
|
|
690 |
* Alignment attribute for aggregates, members and variables.
|
|
691 |
*
|
|
692 |
* `align(<ealign>) <decl...>` or
|
|
693 |
* `align <decl...>` if `ealign` is null
|
|
694 |
*/
|
|
695 |
extern (C++) final class AlignDeclaration : AttribDeclaration |
|
696 |
{
|
|
697 |
Expression ealign; /// expression yielding the actual alignment |
|
698 |
enum structalign_t UNKNOWN = 0; /// alignment not yet computed |
|
699 |
static assert(STRUCTALIGN_DEFAULT != UNKNOWN); |
|
700 |
|
|
701 |
/// the actual alignment, `UNKNOWN` until it's either set to the value of `ealign`
|
|
702 |
/// or `STRUCTALIGN_DEFAULT` if `ealign` is null ( / an error ocurred)
|
|
703 |
structalign_t salign = UNKNOWN; |
|
704 |
|
|
705 |
|
|
706 | 1 |
extern (D) this(const ref Loc loc, Expression ealign, Dsymbols* decl) |
707 |
{
|
|
708 | 1 |
super(loc, null, decl); |
709 | 1 |
this.ealign = ealign; |
710 |
}
|
|
711 |
|
|
712 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
713 |
{
|
|
714 | 1 |
assert(!s); |
715 | 1 |
return new AlignDeclaration(loc, |
716 | 1 |
ealign ? ealign.syntaxCopy() : null, |
717 |
Dsymbol.arraySyntaxCopy(decl)); |
|
718 |
}
|
|
719 |
|
|
720 |
override Scope* newScope(Scope* sc) |
|
721 |
{
|
|
722 | 1 |
return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, this, sc.inlining); |
723 |
}
|
|
724 |
|
|
725 |
override void accept(Visitor v) |
|
726 |
{
|
|
727 | 1 |
v.visit(this); |
728 |
}
|
|
729 |
}
|
|
730 |
|
|
731 |
/***********************************************************
|
|
732 |
* An anonymous struct/union (defined by `isunion`).
|
|
733 |
*/
|
|
734 |
extern (C++) final class AnonDeclaration : AttribDeclaration |
|
735 |
{
|
|
736 |
bool isunion; /// whether it's a union |
|
737 |
int sem; /// 1 if successful semantic() |
|
738 |
uint anonoffset; /// offset of anonymous struct |
|
739 |
uint anonstructsize; /// size of anonymous struct |
|
740 |
uint anonalignsize; /// size of anonymous struct for alignment purposes |
|
741 |
|
|
742 | 1 |
extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl) |
743 |
{
|
|
744 | 1 |
super(loc, null, decl); |
745 | 1 |
this.isunion = isunion; |
746 |
}
|
|
747 |
|
|
748 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
749 |
{
|
|
750 | 1 |
assert(!s); |
751 | 1 |
return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); |
752 |
}
|
|
753 |
|
|
754 |
override void setScope(Scope* sc) |
|
755 |
{
|
|
756 | 1 |
if (decl) |
757 | 1 |
Dsymbol.setScope(sc); |
758 | 1 |
return AttribDeclaration.setScope(sc); |
759 |
}
|
|
760 |
|
|
761 |
override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) |
|
762 |
{
|
|
763 |
//printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
|
|
764 | 1 |
if (decl) |
765 |
{
|
|
766 |
/* This works by treating an AnonDeclaration as an aggregate 'member',
|
|
767 |
* so in order to place that member we need to compute the member's
|
|
768 |
* size and alignment.
|
|
769 |
*/
|
|
770 | 1 |
size_t fieldstart = ad.fields.dim; |
771 |
|
|
772 |
/* Hackishly hijack ad's structsize and alignsize fields
|
|
773 |
* for use in our fake anon aggregate member.
|
|
774 |
*/
|
|
775 | 1 |
uint savestructsize = ad.structsize; |
776 | 1 |
uint savealignsize = ad.alignsize; |
777 | 1 |
ad.structsize = 0; |
778 | 1 |
ad.alignsize = 0; |
779 |
|
|
780 | 1 |
uint offset = 0; |
781 | 1 |
decl.foreachDsymbol( (s) |
782 |
{
|
|
783 | 1 |
s.setFieldOffset(ad, &offset, this.isunion); |
784 | 1 |
if (this.isunion) |
785 | 1 |
offset = 0; |
786 |
});
|
|
787 |
|
|
788 |
/* https://issues.dlang.org/show_bug.cgi?id=13613
|
|
789 |
* If the fields in this.members had been already
|
|
790 |
* added in ad.fields, just update *poffset for the subsequent
|
|
791 |
* field offset calculation.
|
|
792 |
*/
|
|
793 | 1 |
if (fieldstart == ad.fields.dim) |
794 |
{
|
|
795 | 1 |
ad.structsize = savestructsize; |
796 | 1 |
ad.alignsize = savealignsize; |
797 | 1 |
*poffset = ad.structsize; |
798 | 1 |
return; |
799 |
}
|
|
800 |
|
|
801 | 1 |
anonstructsize = ad.structsize; |
802 | 1 |
anonalignsize = ad.alignsize; |
803 | 1 |
ad.structsize = savestructsize; |
804 | 1 |
ad.alignsize = savealignsize; |
805 |
|
|
806 |
// 0 sized structs are set to 1 byte
|
|
807 | 1 |
if (anonstructsize == 0) |
808 |
{
|
|
809 |
anonstructsize = 1; |
|
810 |
anonalignsize = 1; |
|
811 |
}
|
|
812 |
|
|
813 | 1 |
assert(_scope); |
814 | 1 |
auto alignment = _scope.alignment(); |
815 |
|
|
816 |
/* Given the anon 'member's size and alignment,
|
|
817 |
* go ahead and place it.
|
|
818 |
*/
|
|
819 | 1 |
anonoffset = AggregateDeclaration.placeField( |
820 |
poffset, |
|
821 |
anonstructsize, anonalignsize, alignment, |
|
822 |
&ad.structsize, &ad.alignsize, |
|
823 |
isunion); |
|
824 |
|
|
825 |
// Add to the anon fields the base offset of this anonymous aggregate
|
|
826 |
//printf("anon fields, anonoffset = %d\n", anonoffset);
|
|
827 | 1 |
foreach (const i; fieldstart .. ad.fields.dim) |
828 |
{
|
|
829 | 1 |
VarDeclaration v = ad.fields[i]; |
830 |
//printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
|
|
831 | 1 |
v.offset += anonoffset; |
832 |
}
|
|
833 |
}
|
|
834 |
}
|
|
835 |
|
|
836 |
override const(char)* kind() const |
|
837 |
{
|
|
838 | 1 |
return (isunion ? "anonymous union" : "anonymous struct"); |
839 |
}
|
|
840 |
|
|
841 |
override inout(AnonDeclaration) isAnonDeclaration() inout |
|
842 |
{
|
|
843 | 1 |
return this; |
844 |
}
|
|
845 |
|
|
846 |
override void accept(Visitor v) |
|
847 |
{
|
|
848 | 1 |
v.visit(this); |
849 |
}
|
|
850 |
}
|
|
851 |
|
|
852 |
/***********************************************************
|
|
853 |
* Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`,
|
|
854 |
* but not PragmaStatement's like `pragma(msg, "hello");`.
|
|
855 |
*
|
|
856 |
* pragma(<ident>, <args>)
|
|
857 |
*/
|
|
858 |
extern (C++) final class PragmaDeclaration : AttribDeclaration |
|
859 |
{
|
|
860 |
Expressions* args; /// parameters of this pragma |
|
861 |
|
|
862 | 1 |
extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) |
863 |
{
|
|
864 | 1 |
super(loc, ident, decl); |
865 | 1 |
this.args = args; |
866 |
}
|
|
867 |
|
|
868 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
869 |
{
|
|
870 |
//printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
|
|
871 | 1 |
assert(!s); |
872 | 1 |
return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl)); |
873 |
}
|
|
874 |
|
|
875 |
override Scope* newScope(Scope* sc) |
|
876 |
{
|
|
877 | 1 |
if (ident == Id.Pinline) |
878 |
{
|
|
879 | 1 |
PINLINE inlining = PINLINE.default_; |
880 | 1 |
if (!args || args.dim == 0) |
881 | 1 |
inlining = PINLINE.default_; |
882 | 1 |
else if (args.dim != 1) |
883 |
{
|
|
884 | 1 |
error("one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.dim); |
885 | 1 |
args.setDim(1); |
886 | 1 |
(*args)[0] = ErrorExp.get(); |
887 |
}
|
|
888 |
else
|
|
889 |
{
|
|
890 | 1 |
Expression e = (*args)[0]; |
891 | 1 |
if (e.op != TOK.int64 || !e.type.equals(Type.tbool)) |
892 |
{
|
|
893 | 1 |
if (e.op != TOK.error) |
894 |
{
|
|
895 | 1 |
error("pragma(`inline`, `true` or `false`) expected, not `%s`", e.toChars()); |
896 | 1 |
(*args)[0] = ErrorExp.get(); |
897 |
}
|
|
898 |
}
|
|
899 | 1 |
else if (e.isBool(true)) |
900 | 1 |
inlining = PINLINE.always; |
901 | 1 |
else if (e.isBool(false)) |
902 | 1 |
inlining = PINLINE.never; |
903 |
}
|
|
904 | 1 |
return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, inlining); |
905 |
}
|
|
906 | 1 |
if (ident == Id.printf || ident == Id.scanf) |
907 |
{
|
|
908 | 1 |
auto sc2 = sc.push(); |
909 |
|
|
910 | 1 |
if (ident == Id.printf) |
911 |
// Override previous setting, never let both be set
|
|
912 | 1 |
sc2.flags = (sc2.flags & ~SCOPE.scanf) | SCOPE.printf; |
913 |
else
|
|
914 | 1 |
sc2.flags = (sc2.flags & ~SCOPE.printf) | SCOPE.scanf; |
915 |
|
|
916 | 1 |
return sc2; |
917 |
}
|
|
918 | 1 |
return sc; |
919 |
}
|
|
920 |
|
|
921 |
override const(char)* kind() const |
|
922 |
{
|
|
923 | 1 |
return "pragma"; |
924 |
}
|
|
925 |
|
|
926 |
override void accept(Visitor v) |
|
927 |
{
|
|
928 | 1 |
v.visit(this); |
929 |
}
|
|
930 |
}
|
|
931 |
|
|
932 |
/***********************************************************
|
|
933 |
* A conditional compilation declaration, used for `version`
|
|
934 |
* / `debug` and specialized for `static if`.
|
|
935 |
*
|
|
936 |
* <condition> { <decl...> } else { <elsedecl> }
|
|
937 |
*/
|
|
938 |
extern (C++) class ConditionalDeclaration : AttribDeclaration |
|
939 |
{
|
|
940 |
Condition condition; /// condition deciding whether decl or elsedecl applies |
|
941 |
Dsymbols* elsedecl; /// array of Dsymbol's for else block |
|
942 |
|
|
943 | 1 |
extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl) |
944 |
{
|
|
945 | 1 |
super(decl); |
946 |
//printf("ConditionalDeclaration::ConditionalDeclaration()\n");
|
|
947 | 1 |
this.condition = condition; |
948 | 1 |
this.elsedecl = elsedecl; |
949 |
}
|
|
950 |
|
|
951 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
952 |
{
|
|
953 | 1 |
assert(!s); |
954 | 1 |
return new ConditionalDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); |
955 |
}
|
|
956 |
|
|
957 |
override final bool oneMember(Dsymbol* ps, Identifier ident) |
|
958 |
{
|
|
959 |
//printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
|
|
960 | 1 |
if (condition.inc != Include.notComputed) |
961 |
{
|
|
962 | 1 |
Dsymbols* d = condition.include(null) ? decl : elsedecl; |
963 | 1 |
return Dsymbol.oneMembers(d, ps, ident); |
964 |
}
|
|
965 |
else
|
|
966 |
{
|
|
967 | 1 |
bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null); |
968 | 1 |
*ps = null; |
969 | 1 |
return res; |
970 |
}
|
|
971 |
}
|
|
972 |
|
|
973 |
// Decide if 'then' or 'else' code should be included
|
|
974 |
override Dsymbols* include(Scope* sc) |
|
975 |
{
|
|
976 |
//printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope);
|
|
977 |
|
|
978 | 1 |
if (errors) |
979 |
return null; |
|
980 |
|
|
981 | 1 |
assert(condition); |
982 | 1 |
return condition.include(_scope ? _scope : sc) ? decl : elsedecl; |
983 |
}
|
|
984 |
|
|
985 |
override final void addComment(const(char)* comment) |
|
986 |
{
|
|
987 |
/* Because addComment is called by the parser, if we called
|
|
988 |
* include() it would define a version before it was used.
|
|
989 |
* But it's no problem to drill down to both decl and elsedecl,
|
|
990 |
* so that's the workaround.
|
|
991 |
*/
|
|
992 | 1 |
if (comment) |
993 |
{
|
|
994 | 1 |
decl .foreachDsymbol( s => s.addComment(comment) ); |
995 | 1 |
elsedecl.foreachDsymbol( s => s.addComment(comment) ); |
996 |
}
|
|
997 |
}
|
|
998 |
|
|
999 |
override void setScope(Scope* sc) |
|
1000 |
{
|
|
1001 | 1 |
include(sc).foreachDsymbol( s => s.setScope(sc) ); |
1002 |
}
|
|
1003 |
|
|
1004 |
override void accept(Visitor v) |
|
1005 |
{
|
|
1006 | 1 |
v.visit(this); |
1007 |
}
|
|
1008 |
}
|
|
1009 |
|
|
1010 |
/***********************************************************
|
|
1011 |
* `<scopesym> {
|
|
1012 |
* static if (<condition>) { <decl> } else { <elsedecl> }
|
|
1013 |
* }`
|
|
1014 |
*/
|
|
1015 |
extern (C++) final class StaticIfDeclaration : ConditionalDeclaration |
|
1016 |
{
|
|
1017 |
ScopeDsymbol scopesym; /// enclosing symbol (e.g. module) where symbols will be inserted |
|
1018 |
private bool addisdone = false; /// true if members have been added to scope |
|
1019 |
private bool onStack = false; /// true if a call to `include` is currently active |
|
1020 |
|
|
1021 | 1 |
extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl) |
1022 |
{
|
|
1023 | 1 |
super(condition, decl, elsedecl); |
1024 |
//printf("StaticIfDeclaration::StaticIfDeclaration()\n");
|
|
1025 |
}
|
|
1026 |
|
|
1027 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
1028 |
{
|
|
1029 | 1 |
assert(!s); |
1030 | 1 |
return new StaticIfDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); |
1031 |
}
|
|
1032 |
|
|
1033 |
/****************************************
|
|
1034 |
* Different from other AttribDeclaration subclasses, include() call requires
|
|
1035 |
* the completion of addMember and setScope phases.
|
|
1036 |
*/
|
|
1037 |
override Dsymbols* include(Scope* sc) |
|
1038 |
{
|
|
1039 |
//printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope);
|
|
1040 |
|
|
1041 | 1 |
if (errors || onStack) |
1042 | 1 |
return null; |
1043 | 1 |
onStack = true; |
1044 | 1 |
scope(exit) onStack = false; |
1045 |
|
|
1046 | 1 |
if (sc && condition.inc == Include.notComputed) |
1047 |
{
|
|
1048 | 1 |
assert(scopesym); // addMember is already done |
1049 | 1 |
assert(_scope); // setScope is already done |
1050 | 1 |
Dsymbols* d = ConditionalDeclaration.include(_scope); |
1051 | 1 |
if (d && !addisdone) |
1052 |
{
|
|
1053 |
// Add members lazily.
|
|
1054 | 1 |
d.foreachDsymbol( s => s.addMember(_scope, scopesym) ); |
1055 |
|
|
1056 |
// Set the member scopes lazily.
|
|
1057 | 1 |
d.foreachDsymbol( s => s.setScope(_scope) ); |
1058 |
|
|
1059 | 1 |
addisdone = true; |
1060 |
}
|
|
1061 | 1 |
return d; |
1062 |
}
|
|
1063 |
else
|
|
1064 |
{
|
|
1065 | 1 |
return ConditionalDeclaration.include(sc); |
1066 |
}
|
|
1067 |
}
|
|
1068 |
|
|
1069 |
override void addMember(Scope* sc, ScopeDsymbol sds) |
|
1070 |
{
|
|
1071 |
//printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
|
|
1072 |
/* This is deferred until the condition evaluated later (by the include() call),
|
|
1073 |
* so that expressions in the condition can refer to declarations
|
|
1074 |
* in the same scope, such as:
|
|
1075 |
*
|
|
1076 |
* template Foo(int i)
|
|
1077 |
* {
|
|
1078 |
* const int j = i + 1;
|
|
1079 |
* static if (j == 3)
|
|
1080 |
* const int k;
|
|
1081 |
* }
|
|
1082 |
*/
|
|
1083 | 1 |
this.scopesym = sds; |
1084 |
}
|
|
1085 |
|
|
1086 |
override void setScope(Scope* sc) |
|
1087 |
{
|
|
1088 |
// do not evaluate condition before semantic pass
|
|
1089 |
// But do set the scope, in case we need it for forward referencing
|
|
1090 | 1 |
Dsymbol.setScope(sc); |
1091 |
}
|
|
1092 |
|
|
1093 |
override void importAll(Scope* sc) |
|
1094 |
{
|
|
1095 |
// do not evaluate condition before semantic pass
|
|
1096 |
}
|
|
1097 |
|
|
1098 |
override const(char)* kind() const |
|
1099 |
{
|
|
1100 |
return "static if"; |
|
1101 |
}
|
|
1102 |
|
|
1103 |
override void accept(Visitor v) |
|
1104 |
{
|
|
1105 | 1 |
v.visit(this); |
1106 |
}
|
|
1107 |
}
|
|
1108 |
|
|
1109 |
/***********************************************************
|
|
1110 |
* Static foreach at declaration scope, like:
|
|
1111 |
* static foreach (i; [0, 1, 2]){ }
|
|
1112 |
*/
|
|
1113 |
|
|
1114 |
extern (C++) final class StaticForeachDeclaration : AttribDeclaration |
|
1115 |
{
|
|
1116 |
StaticForeach sfe; /// contains `static foreach` expansion logic |
|
1117 |
|
|
1118 |
ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration) |
|
1119 |
|
|
1120 |
/++
|
|
1121 |
`include` can be called multiple times, but a `static foreach`
|
|
1122 |
should be expanded at most once. Achieved by caching the result
|
|
1123 |
of the first call. We need both `cached` and `cache`, because
|
|
1124 |
`null` is a valid value for `cache`.
|
|
1125 |
+/
|
|
1126 |
bool onStack = false; |
|
1127 |
bool cached = false; |
|
1128 |
Dsymbols* cache = null; |
|
1129 |
|
|
1130 | 1 |
extern (D) this(StaticForeach sfe, Dsymbols* decl) |
1131 |
{
|
|
1132 | 1 |
super(decl); |
1133 | 1 |
this.sfe = sfe; |
1134 |
}
|
|
1135 |
|
|
1136 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
1137 |
{
|
|
1138 | 1 |
assert(!s); |
1139 | 1 |
return new StaticForeachDeclaration( |
1140 |
sfe.syntaxCopy(), |
|
1141 |
Dsymbol.arraySyntaxCopy(decl)); |
|
1142 |
}
|
|
1143 |
|
|
1144 |
override bool oneMember(Dsymbol* ps, Identifier ident) |
|
1145 |
{
|
|
1146 |
// Required to support IFTI on a template that contains a
|
|
1147 |
// `static foreach` declaration. `super.oneMember` calls
|
|
1148 |
// include with a `null` scope. As `static foreach` requires
|
|
1149 |
// the scope for expansion, `oneMember` can only return a
|
|
1150 |
// precise result once `static foreach` has been expanded.
|
|
1151 | 1 |
if (cached) |
1152 |
{
|
|
1153 | 1 |
return super.oneMember(ps, ident); |
1154 |
}
|
|
1155 | 1 |
*ps = null; // a `static foreach` declaration may in general expand to multiple symbols |
1156 | 1 |
return false; |
1157 |
}
|
|
1158 |
|
|
1159 |
override Dsymbols* include(Scope* sc) |
|
1160 |
{
|
|
1161 | 1 |
if (errors || onStack) |
1162 | 1 |
return null; |
1163 | 1 |
if (cached) |
1164 |
{
|
|
1165 | 1 |
assert(!onStack); |
1166 | 1 |
return cache; |
1167 |
}
|
|
1168 | 1 |
onStack = true; |
1169 | 1 |
scope(exit) onStack = false; |
1170 |
|
|
1171 | 1 |
if (_scope) |
1172 |
{
|
|
1173 | 1 |
sfe.prepare(_scope); // lower static foreach aggregate |
1174 |
}
|
|
1175 | 1 |
if (!sfe.ready()) |
1176 |
{
|
|
1177 | 1 |
return null; // TODO: ok? |
1178 |
}
|
|
1179 |
|
|
1180 |
// expand static foreach
|
|
1181 |
import dmd.statementsem: makeTupleForeach; |
|
1182 | 1 |
Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion); |
1183 | 1 |
if (d) // process generated declarations |
1184 |
{
|
|
1185 |
// Add members lazily.
|
|
1186 | 1 |
d.foreachDsymbol( s => s.addMember(_scope, scopesym) ); |
1187 |
|
|
1188 |
// Set the member scopes lazily.
|
|
1189 | 1 |
d.foreachDsymbol( s => s.setScope(_scope) ); |
1190 |
}
|
|
1191 | 1 |
cached = true; |
1192 | 1 |
cache = d; |
1193 | 1 |
return d; |
1194 |
}
|
|
1195 |
|
|
1196 |
override void addMember(Scope* sc, ScopeDsymbol sds) |
|
1197 |
{
|
|
1198 |
// used only for caching the enclosing symbol
|
|
1199 | 1 |
this.scopesym = sds; |
1200 |
}
|
|
1201 |
|
|
1202 |
override void addComment(const(char)* comment) |
|
1203 |
{
|
|
1204 |
// do nothing
|
|
1205 |
// change this to give semantics to documentation comments on static foreach declarations
|
|
1206 |
}
|
|
1207 |
|
|
1208 |
override void setScope(Scope* sc) |
|
1209 |
{
|
|
1210 |
// do not evaluate condition before semantic pass
|
|
1211 |
// But do set the scope, in case we need it for forward referencing
|
|
1212 | 1 |
Dsymbol.setScope(sc); |
1213 |
}
|
|
1214 |
|
|
1215 |
override void importAll(Scope* sc) |
|
1216 |
{
|
|
1217 |
// do not evaluate aggregate before semantic pass
|
|
1218 |
}
|
|
1219 |
|
|
1220 |
override const(char)* kind() const |
|
1221 |
{
|
|
1222 |
return "static foreach"; |
|
1223 |
}
|
|
1224 |
|
|
1225 |
override void accept(Visitor v) |
|
1226 |
{
|
|
1227 | 1 |
v.visit(this); |
1228 |
}
|
|
1229 |
}
|
|
1230 |
|
|
1231 |
/***********************************************************
|
|
1232 |
* Collection of declarations that stores foreach index variables in a
|
|
1233 |
* local symbol table. Other symbols declared within are forwarded to
|
|
1234 |
* another scope, like:
|
|
1235 |
*
|
|
1236 |
* static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
|
|
1237 |
* { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local
|
|
1238 |
* mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
|
|
1239 |
* }
|
|
1240 |
*
|
|
1241 |
* static foreach (i; 0.. 10)
|
|
1242 |
* {
|
|
1243 |
* pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
|
|
1244 |
* }
|
|
1245 |
*
|
|
1246 |
* static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
|
|
1247 |
*
|
|
1248 |
* A StaticForeachDeclaration generates one
|
|
1249 |
* ForwardingAttribDeclaration for each expansion of its body. The
|
|
1250 |
* AST of the ForwardingAttribDeclaration contains both the `static
|
|
1251 |
* foreach` variables and the respective copy of the `static foreach`
|
|
1252 |
* body. The functionality is achieved by using a
|
|
1253 |
* ForwardingScopeDsymbol as the parent symbol for the generated
|
|
1254 |
* declarations.
|
|
1255 |
*/
|
|
1256 |
|
|
1257 |
extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration |
|
1258 |
{
|
|
1259 |
ForwardingScopeDsymbol sym = null; |
|
1260 |
|
|
1261 | 1 |
this(Dsymbols* decl) |
1262 |
{
|
|
1263 | 1 |
super(decl); |
1264 | 1 |
sym = new ForwardingScopeDsymbol(null); |
1265 | 1 |
sym.symtab = new DsymbolTable(); |
1266 |
}
|
|
1267 |
|
|
1268 |
/**************************************
|
|
1269 |
* Use the ForwardingScopeDsymbol as the parent symbol for members.
|
|
1270 |
*/
|
|
1271 |
override Scope* newScope(Scope* sc) |
|
1272 |
{
|
|
1273 | 1 |
return sc.push(sym); |
1274 |
}
|
|
1275 |
|
|
1276 |
/***************************************
|
|
1277 |
* Lazily initializes the scope to forward to.
|
|
1278 |
*/
|
|
1279 |
override void addMember(Scope* sc, ScopeDsymbol sds) |
|
1280 |
{
|
|
1281 | 1 |
parent = sym.parent = sym.forward = sds; |
1282 | 1 |
return super.addMember(sc, sym); |
1283 |
}
|
|
1284 |
|
|
1285 |
override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout |
|
1286 |
{
|
|
1287 |
return this; |
|
1288 |
}
|
|
1289 |
|
|
1290 |
override void accept(Visitor v) |
|
1291 |
{
|
|
1292 | 1 |
v.visit(this); |
1293 |
}
|
|
1294 |
}
|
|
1295 |
|
|
1296 |
|
|
1297 |
/***********************************************************
|
|
1298 |
* Mixin declarations, like:
|
|
1299 |
* mixin("int x");
|
|
1300 |
* https://dlang.org/spec/module.html#mixin-declaration
|
|
1301 |
*/
|
|
1302 |
extern (C++) final class CompileDeclaration : AttribDeclaration |
|
1303 |
{
|
|
1304 |
Expressions* exps; |
|
1305 |
ScopeDsymbol scopesym; |
|
1306 |
bool compiled; |
|
1307 |
|
|
1308 | 1 |
extern (D) this(const ref Loc loc, Expressions* exps) |
1309 |
{
|
|
1310 | 1 |
super(loc, null, null); |
1311 |
//printf("CompileDeclaration(loc = %d)\n", loc.linnum);
|
|
1312 | 1 |
this.exps = exps; |
1313 |
}
|
|
1314 |
|
|
1315 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
1316 |
{
|
|
1317 |
//printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
|
|
1318 | 1 |
return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps)); |
1319 |
}
|
|
1320 |
|
|
1321 |
override void addMember(Scope* sc, ScopeDsymbol sds) |
|
1322 |
{
|
|
1323 |
//printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
|
|
1324 | 1 |
this.scopesym = sds; |
1325 |
}
|
|
1326 |
|
|
1327 |
override void setScope(Scope* sc) |
|
1328 |
{
|
|
1329 | 1 |
Dsymbol.setScope(sc); |
1330 |
}
|
|
1331 |
|
|
1332 |
override const(char)* kind() const |
|
1333 |
{
|
|
1334 |
return "mixin"; |
|
1335 |
}
|
|
1336 |
|
|
1337 |
override inout(CompileDeclaration) isCompileDeclaration() inout |
|
1338 |
{
|
|
1339 | 1 |
return this; |
1340 |
}
|
|
1341 |
|
|
1342 |
override void accept(Visitor v) |
|
1343 |
{
|
|
1344 | 1 |
v.visit(this); |
1345 |
}
|
|
1346 |
}
|
|
1347 |
|
|
1348 |
/***********************************************************
|
|
1349 |
* User defined attributes look like:
|
|
1350 |
* @foo(args, ...)
|
|
1351 |
* @(args, ...)
|
|
1352 |
*/
|
|
1353 |
extern (C++) final class UserAttributeDeclaration : AttribDeclaration |
|
1354 |
{
|
|
1355 |
Expressions* atts; |
|
1356 |
|
|
1357 | 1 |
extern (D) this(Expressions* atts, Dsymbols* decl) |
1358 |
{
|
|
1359 | 1 |
super(decl); |
1360 |
//printf("UserAttributeDeclaration()\n");
|
|
1361 | 1 |
this.atts = atts; |
1362 |
}
|
|
1363 |
|
|
1364 |
override Dsymbol syntaxCopy(Dsymbol s) |
|
1365 |
{
|
|
1366 |
//printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
|
|
1367 | 1 |
assert(!s); |
1368 | 1 |
return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl)); |
1369 |
}
|
|
1370 |
|
|
1371 |
override Scope* newScope(Scope* sc) |
|
1372 |
{
|
|
1373 | 1 |
Scope* sc2 = sc; |
1374 | 1 |
if (atts && atts.dim) |
1375 |
{
|
|
1376 |
// create new one for changes
|
|
1377 | 1 |
sc2 = sc.copy(); |
1378 | 1 |
sc2.userAttribDecl = this; |
1379 |
}
|
|
1380 | 1 |
return sc2; |
1381 |
}
|
|
1382 |
|
|
1383 |
override void setScope(Scope* sc) |
|
1384 |
{
|
|
1385 |
//printf("UserAttributeDeclaration::setScope() %p\n", this);
|
|
1386 | 1 |
if (decl) |
1387 | 1 |
Dsymbol.setScope(sc); // for forward reference of UDAs |
1388 | 1 |
return AttribDeclaration.setScope(sc); |
1389 |
}
|
|
1390 |
|
|
1391 |
extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2) |
|
1392 |
{
|
|
1393 | 1 |
Expressions* udas; |
1394 | 1 |
if (!udas1 || udas1.dim == 0) |
1395 | 1 |
udas = udas2; |
1396 | 1 |
else if (!udas2 || udas2.dim == 0) |
1397 | 1 |
udas = udas1; |
1398 |
else
|
|
1399 |
{
|
|
1400 |
/* Create a new tuple that combines them
|
|
1401 |
* (do not append to left operand, as this is a copy-on-write operation)
|
|
1402 |
*/
|
|
1403 | 1 |
udas = new Expressions(2); |
1404 | 1 |
(*udas)[0] = new TupleExp(Loc.initial, udas1); |
1405 | 1 |
(*udas)[1] = new TupleExp(Loc.initial, udas2); |
1406 |
}
|
|
1407 | 1 |
return udas; |
1408 |
}
|
|
1409 |
|
|
1410 |
Expressions* getAttributes() |
|
1411 |
{
|
|
1412 | 1 |
if (auto sc = _scope) |
1413 |
{
|
|
1414 | 1 |
_scope = null; |
1415 | 1 |
arrayExpressionSemantic(atts, sc); |
1416 |
}
|
|
1417 | 1 |
auto exps = new Expressions(); |
1418 | 1 |
if (userAttribDecl && userAttribDecl !is this) |
1419 | 1 |
exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes())); |
1420 | 1 |
if (atts && atts.dim) |
1421 | 1 |
exps.push(new TupleExp(Loc.initial, atts)); |
1422 | 1 |
return exps; |
1423 |
}
|
|
1424 |
|
|
1425 |
override const(char)* kind() const |
|
1426 |
{
|
|
1427 |
return "UserAttribute"; |
|
1428 |
}
|
|
1429 |
|
|
1430 |
override void accept(Visitor v) |
|
1431 |
{
|
|
1432 | 1 |
v.visit(this); |
1433 |
}
|
|
1434 |
|
|
1435 |
/**
|
|
1436 |
* Check if the provided expression references `core.attribute.gnuAbiTag`
|
|
1437 |
*
|
|
1438 |
* This should be called after semantic has been run on the expression.
|
|
1439 |
* Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
|
|
1440 |
*
|
|
1441 |
* Params:
|
|
1442 |
* e = Expression to check (usually from `UserAttributeDeclaration.atts`)
|
|
1443 |
*
|
|
1444 |
* Returns:
|
|
1445 |
* `true` if the expression references the compiler-recognized `gnuAbiTag`
|
|
1446 |
*/
|
|
1447 |
static bool isGNUABITag(Expression e) |
|
1448 |
{
|
|
1449 | 1 |
if (global.params.cplusplus < CppStdRevision.cpp11) |
1450 | 1 |
return false; |
1451 |
|
|
1452 | 1 |
auto ts = e.type ? e.type.isTypeStruct() : null; |
1453 | 1 |
if (!ts) |
1454 | 1 |
return false; |
1455 | 1 |
if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent) |
1456 |
return false; |
|
1457 |
// Can only be defined in druntime
|
|
1458 | 1 |
Module m = ts.sym.parent.isModule(); |
1459 | 1 |
if (!m || !m.isCoreModule(Id.attribute)) |
1460 | 1 |
return false; |
1461 | 1 |
return true; |
1462 |
}
|
|
1463 |
|
|
1464 |
/**
|
|
1465 |
* Called from a symbol's semantic to check if `gnuAbiTag` UDA
|
|
1466 |
* can be applied to them
|
|
1467 |
*
|
|
1468 |
* Directly emits an error if the UDA doesn't work with this symbol
|
|
1469 |
*
|
|
1470 |
* Params:
|
|
1471 |
* sym = symbol to check for `gnuAbiTag`
|
|
1472 |
* linkage = Linkage of the symbol (Declaration.link or sc.link)
|
|
1473 |
*/
|
|
1474 |
static void checkGNUABITag(Dsymbol sym, LINK linkage) |
|
1475 |
{
|
|
1476 | 1 |
if (global.params.cplusplus < CppStdRevision.cpp11) |
1477 | 1 |
return; |
1478 |
|
|
1479 |
// Avoid `if` at the call site
|
|
1480 | 1 |
if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null) |
1481 | 1 |
return; |
1482 |
|
|
1483 | 1 |
foreach (exp; *sym.userAttribDecl.atts) |
1484 |
{
|
|
1485 | 1 |
if (isGNUABITag(exp)) |
1486 |
{
|
|
1487 | 1 |
if (sym.isCPPNamespaceDeclaration() || sym.isNspace()) |
1488 |
{
|
|
1489 | 1 |
exp.error("`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars()); |
1490 | 1 |
sym.errors = true; |
1491 |
}
|
|
1492 | 1 |
else if (linkage != LINK.cpp) |
1493 |
{
|
|
1494 | 1 |
exp.error("`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars()); |
1495 | 1 |
sym.errors = true; |
1496 |
}
|
|
1497 |
// Only one `@gnuAbiTag` is allowed by semantic2
|
|
1498 | 1 |
return; |
1499 |
}
|
|
1500 |
}
|
|
1501 |
}
|
|
1502 |
}
|
Read our documentation on viewing source code .