1 /** 2 * A scoped C++ namespace symbol 3 * 4 * D supports the following syntax to declare symbol(s) as being part of a 5 * C++ namespace: 6 * --- 7 * extern (C++, "myNamespace") { /+ Symbols +/ } // String variant 8 * extern (C++, SomeNamespace) { /+ Other symbols +/ } // Identifier variant 9 * --- 10 * The first form is an attribute and only affects mangling, and is implemented 11 * in `dmd.attrib`. 12 * The second form introduces a named scope and allows symbols to be refered 13 * to with or without the namespace name, much like a named template mixin, 14 * and is implemented in this module. 15 * --- 16 * extern (C++, Basket) 17 * { 18 * struct StrawBerry; 19 * void swapFood (Strawberry* f1, Strawberry* f2); 20 * } 21 * void main () 22 * { 23 * Basket.StrawBerry fruit1; 24 * StrawBerry fruit2; 25 * Basket.swapFood(fruit1, fruit2); 26 * swapFood(fruit1, fruit2); 27 * } 28 * --- 29 * Hence the `Nspace` symbol implements the usual `ScopeDsymbol` semantics. 30 * 31 * Note that it implies `extern(C++)` so it cannot be used as a generic 32 * named scope. Additionally, `Nspace` with the same `Identifier` can be 33 * defined in different module (as C++ allows a namespace to be spread accross 34 * translation units), but symbols in it should be considered 35 * part of the same scope. Lastly, not all possible C++ namespace names 36 * are valid D identifier. 37 * 38 * See_Also: https://github.com/dlang/dmd/pull/10031 39 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 40 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 41 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 42 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d) 43 * Documentation: https://dlang.org/phobos/dmd_nspace.html 44 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nspace.d 45 */ 46 47 module dmd.nspace; 48 49 import dmd.aggregate; 50 import dmd.arraytypes; 51 import dmd.astenums; 52 import dmd.dscope; 53 import dmd.dsymbol; 54 import dmd.dsymbolsem; 55 import dmd.errors; 56 import dmd.expression; 57 import dmd.globals; 58 import dmd.identifier; 59 import dmd.location; 60 import dmd.visitor; 61 import core.stdc.stdio; 62 63 private enum LOG = false; 64 65 /// Ditto 66 extern (C++) final class Nspace : ScopeDsymbol 67 { 68 /** 69 * Namespace identifier resolved during semantic. 70 */ 71 Expression identExp; 72 73 extern (D) this(const ref Loc loc, Identifier ident, Expression identExp, Dsymbols* members) 74 { 75 super(loc, ident); 76 //printf("Nspace::Nspace(ident = %s)\n", ident.toChars()); 77 this.members = members; 78 this.identExp = identExp; 79 } 80 81 override Nspace syntaxCopy(Dsymbol s) 82 { 83 auto ns = new Nspace(loc, ident, identExp, null); 84 ScopeDsymbol.syntaxCopy(ns); 85 return ns; 86 } 87 88 override void addMember(Scope* sc, ScopeDsymbol sds) 89 { 90 ScopeDsymbol.addMember(sc, sds); 91 92 if (members) 93 { 94 if (!symtab) 95 symtab = new DsymbolTable(); 96 // The namespace becomes 'imported' into the enclosing scope 97 for (Scope* sce = sc; 1; sce = sce.enclosing) 98 { 99 ScopeDsymbol sds2 = sce.scopesym; 100 if (sds2) 101 { 102 sds2.importScope(this, Visibility(Visibility.Kind.public_)); 103 break; 104 } 105 } 106 assert(sc); 107 sc = sc.push(this); 108 sc.linkage = LINK.cpp; // namespaces default to C++ linkage 109 sc.parent = this; 110 members.foreachDsymbol(s => s.addMember(sc, this)); 111 sc.pop(); 112 } 113 } 114 115 override void setScope(Scope* sc) 116 { 117 ScopeDsymbol.setScope(sc); 118 if (members) 119 { 120 assert(sc); 121 sc = sc.push(this); 122 sc.linkage = LINK.cpp; // namespaces default to C++ linkage 123 sc.parent = this; 124 members.foreachDsymbol(s => s.setScope(sc)); 125 sc.pop(); 126 } 127 } 128 129 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 130 { 131 //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars()); 132 if (_scope && !symtab) 133 dsymbolSemantic(this, _scope); 134 135 if (!members || !symtab) // opaque or semantic() is not yet called 136 { 137 if (!(flags & IgnoreErrors)) 138 .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars()); 139 return null; 140 } 141 142 return ScopeDsymbol.search(loc, ident, flags); 143 } 144 145 override bool hasPointers() 146 { 147 //printf("Nspace::hasPointers() %s\n", toChars()); 148 return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; 149 } 150 151 override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) 152 { 153 //printf("Nspace::setFieldOffset() %s\n", toChars()); 154 if (_scope) // if fwd reference 155 dsymbolSemantic(this, null); // try to resolve it 156 members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); 157 } 158 159 override const(char)* kind() const 160 { 161 return "namespace"; 162 } 163 164 override inout(Nspace) isNspace() inout 165 { 166 return this; 167 } 168 169 override void accept(Visitor v) 170 { 171 v.visit(this); 172 } 173 }