1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <cmajor/symbols/VariableSymbol.hpp>
  7 #include <cmajor/symbols/TypeSymbol.hpp>
  8 #include <cmajor/symbols/SymbolTable.hpp>
  9 #include <cmajor/symbols/SymbolWriter.hpp>
 10 #include <cmajor/symbols/SymbolReader.hpp>
 11 #include <cmajor/symbols/Exception.hpp>
 12 #include <cmajor/symbols/SymbolCollector.hpp>
 13 #include <cmajor/symbols/Module.hpp>
 14 #include <soulng/util/Unicode.hpp>
 15 #include <soulng/util/Sha1.hpp>
 16 #include <algorithm>
 17 
 18 namespace cmajor { namespace symbols {
 19 
 20 using namespace soulng::unicode;
 21 
 22 VariableSymbol::VariableSymbol(SymbolType symbolType_const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) :
 23     Symbol(symbolType_span_sourceModuleId_name_)type()
 24 {
 25 }
 26 
 27 void VariableSymbol::Write(SymbolWriter& writer)
 28 {
 29     Symbol::Write(writer);
 30     writer.GetBinaryWriter().Write(type->TypeId());
 31 }
 32 
 33 void VariableSymbol::Read(SymbolReader& reader)
 34 {
 35     Symbol::Read(reader);
 36     boost::uuids::uuid typeId;
 37     reader.GetBinaryReader().ReadUuid(typeId);
 38     reader.GetSymbolTable()->EmplaceTypeRequest(readerthistypeId0);
 39 }
 40 
 41 void VariableSymbol::EmplaceType(TypeSymbol* typeSymbolint index)
 42 {
 43     Assert(index == 0"invalid emplace type index");
 44     type = typeSymbol;
 45 }
 46 
 47 const ContainerScope* VariableSymbol::GetTypeScope() const
 48 {
 49     if (type)
 50     {
 51         return type->BaseType()->GetContainerScope();
 52     }
 53     else
 54     {
 55         return nullptr;
 56     }
 57 }
 58 
 59 ContainerScope* VariableSymbol::GetTypeScope()
 60 {
 61     if (type)
 62     {
 63         return type->BaseType()->GetContainerScope();
 64     }
 65     else
 66     {
 67         return nullptr;
 68     }
 69 }
 70 
 71 void VariableSymbol::Check()
 72 {
 73     Symbol::Check();
 74     if (!type)
 75     {
 76         throw SymbolCheckException("variable symbol contains null type pointer"GetSpan()SourceModuleId());
 77     }
 78 }
 79 
 80 std::string VariableSymbol::GetSymbolHelp() const
 81 {
 82     if (!type) return std::string();
 83     std::string help = "(";
 84     help.append(GetSymbolCategoryDescription()).append(") ");
 85     help.append(ToUtf8(type->FullName())).append(" ");
 86     help.append(ToUtf8(FullName()));
 87     return help;
 88 }
 89 
 90 ParameterSymbol::ParameterSymbol(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) :
 91     VariableSymbol(SymbolType::parameterSymbolspan_sourceModuleId_name_)artificialName(false)
 92 {
 93 }
 94 
 95 void ParameterSymbol::Write(SymbolWriter& writer)
 96 {
 97     VariableSymbol::Write(writer);
 98     writer.GetBinaryWriter().Write(artificialName);
 99 }
100 
101 void ParameterSymbol::Read(SymbolReader& reader)
102 {
103     VariableSymbol::Read(reader);
104     artificialName = reader.GetBinaryReader().ReadBool();
105 }
106 
107 bool ParameterSymbol::IsExportSymbol() const
108 {
109     return VariableSymbol::IsExportSymbol();
110 }
111 
112 std::u32string ParameterSymbol::CodeName() const
113 {
114     if (artificialName)
115     {
116         return std::u32string();
117     }
118     return VariableSymbol::CodeName();
119 }
120 
121 std::std::unique_ptr<sngxml::dom::Element>ParameterSymbol::CreateDomElement(TypeMap&typeMap)
122 {
123     std::unique_ptr<sngxml::dom::Element> element(new sngxml::dom::Element(U"ParameterSymbol"));
124     if (GetType())
125     {
126         std::unique_ptr<sngxml::dom::Element> typeElement(new sngxml::dom::Element(U"type"));
127         int typeId = typeMap.GetOrInsertType(GetType());
128         typeElement->SetAttribute(U"ref"U"type_" + ToUtf32(std::to_string(typeId)));
129         element->AppendChild(std::unique_ptr<sngxml::dom::Node>(typeElement.release()));
130     }
131     return element;
132 }
133 
134 ParameterSymbol* ParameterSymbol::Clone() const
135 {
136     ParameterSymbol* clone = new ParameterSymbol(GetSpan()SourceModuleId()Name());
137     clone->SetType(const_cast<TypeSymbol*>(GetType()));
138     clone->artificialName = artificialName;
139     return clone;
140 }
141 
142 std::string ParameterSymbol::GetSymbolHelp() const
143 {
144     if (!GetType()) return std::string();
145     std::string help = "(";
146     help.append(GetSymbolCategoryDescription()).append(") ");
147     help.append(ToUtf8(GetType()->FullName())).append(" ");
148     help.append(ToUtf8(Name()));
149     return help;
150 }
151 
152 LocalVariableSymbol::LocalVariableSymbol(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) :
153     VariableSymbol(SymbolType::localVariableSymbolspan_sourceModuleId_name_)
154 {
155 }
156 
157 std::std::unique_ptr<sngxml::dom::Element>LocalVariableSymbol::CreateDomElement(TypeMap&typeMap)
158 {
159     std::unique_ptr<sngxml::dom::Element> element(new sngxml::dom::Element(U"LocalVariableSymbol"));
160     if (GetType())
161     {
162         std::unique_ptr<sngxml::dom::Element> typeElement(new sngxml::dom::Element(U"type"));
163         int typeId = typeMap.GetOrInsertType(GetType());
164         typeElement->SetAttribute(U"ref"U"type_" + ToUtf32(std::to_string(typeId)));
165         element->AppendChild(std::unique_ptr<sngxml::dom::Node>(typeElement.release()));
166     }
167     return element;
168 }
169 
170 std::string LocalVariableSymbol::GetSymbolHelp() const
171 {
172     if (!GetType()) return std::string();
173     std::string help = "(";
174     help.append(GetSymbolCategoryDescription()).append(") ");
175     help.append(ToUtf8(GetType()->FullName())).append(" ");
176     help.append(ToUtf8(Name()));
177     return help;
178 }
179 
180 MemberVariableSymbol::MemberVariableSymbol(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) :
181     VariableSymbol(SymbolType::memberVariableSymbolspan_sourceModuleId_name_)layoutIndex(-1)
182 {
183 }
184 
185 void MemberVariableSymbol::Write(SymbolWriter& writer)
186 {
187     VariableSymbol::Write(writer);
188     writer.GetBinaryWriter().Write(layoutIndex);
189 }
190 
191 void MemberVariableSymbol::Read(SymbolReader& reader)
192 {
193     VariableSymbol::Read(reader);
194     layoutIndex = reader.GetBinaryReader().ReadInt();
195 }
196 
197 bool MemberVariableSymbol::IsExportSymbol() const
198 {
199     return VariableSymbol::IsExportSymbol();
200 }
201 
202 void MemberVariableSymbol::Accept(SymbolCollector* collector)
203 {
204     if (IsProject() && Access() == SymbolAccess::public_)
205     {
206         collector->AddMemberVariable(this);
207     }
208 }
209 
210 void MemberVariableSymbol::Dump(CodeFormatter& formatter)
211 {
212     formatter.WriteLine(ToUtf8(Name()));
213     formatter.WriteLine("full name: " + ToUtf8(FullNameWithSpecifiers()));
214     formatter.WriteLine("mangled name: " + ToUtf8(MangledName()));
215     formatter.WriteLine("type: " + ToUtf8(GetType()->FullName()));
216     formatter.WriteLine("layout index: " + std::to_string(layoutIndex));
217 }
218 
219 std::string MemberVariableSymbol::Syntax() const
220 {
221     std::string syntax = GetSpecifierStr();
222     if (!syntax.empty())
223     {
224         syntax.append(1' ');
225     }
226     syntax.append(ToUtf8(GetType()->DocName()));
227     syntax.append(1' ');
228     syntax.append(ToUtf8(DocName()));
229     syntax.append(1';');
230     return syntax;
231 }
232 
233 void MemberVariableSymbol::SetSpecifiers(Specifiers specifiers)
234 {
235     Specifiers accessSpecifiers = specifiers & Specifiers::access_;
236     SetAccess(accessSpecifiers);
237     if ((specifiers & Specifiers::static_) != Specifiers::none)
238     {
239         SetStatic();
240     }
241     if ((specifiers & Specifiers::virtual_) != Specifiers::none)
242     {
243         throw Exception("member variable cannot be virtual"GetSpan()SourceModuleId());
244     }
245     if ((specifiers & Specifiers::override_) != Specifiers::none)
246     {
247         throw Exception("member variable cannot be override"GetSpan()SourceModuleId());
248     }
249     if ((specifiers & Specifiers::abstract_) != Specifiers::none)
250     {
251         throw Exception("member variable cannot be abstract"GetSpan()SourceModuleId());
252     }
253     if ((specifiers & Specifiers::inline_) != Specifiers::none)
254     {
255         throw Exception("member variable cannot be inline"GetSpan()SourceModuleId());
256     }
257     if ((specifiers & Specifiers::explicit_) != Specifiers::none)
258     {
259         throw Exception("member variable cannot be explicit"GetSpan()SourceModuleId());
260     }
261     if ((specifiers & Specifiers::external_) != Specifiers::none)
262     {
263         throw Exception("member variable cannot be external"GetSpan()SourceModuleId());
264     }
265     if ((specifiers & Specifiers::suppress_) != Specifiers::none)
266     {
267         throw Exception("member variable cannot be suppressed"GetSpan()SourceModuleId());
268     }
269     if ((specifiers & Specifiers::default_) != Specifiers::none)
270     {
271         throw Exception("member variable cannot be default"GetSpan()SourceModuleId());
272     }
273     if ((specifiers & Specifiers::constexpr_) != Specifiers::none)
274     {
275         throw Exception("member variable cannot be constexpr"GetSpan()SourceModuleId());
276     }
277     if ((specifiers & Specifiers::cdecl_) != Specifiers::none)
278     {
279         throw Exception("member variable cannot be cdecl"GetSpan()SourceModuleId());
280     }
281     if ((specifiers & Specifiers::nothrow_) != Specifiers::none)
282     {
283         throw Exception("member variable cannot be nothrow"GetSpan()SourceModuleId());
284     }
285     if ((specifiers & Specifiers::throw_) != Specifiers::none)
286     {
287         throw Exception("member variable cannot be throw"GetSpan()SourceModuleId());
288     }
289     if ((specifiers & Specifiers::new_) != Specifiers::none)
290     {
291         throw Exception("member variable cannot be new"GetSpan()SourceModuleId());
292     }
293     if ((specifiers & Specifiers::const_) != Specifiers::none)
294     {
295         throw Exception("member variable cannot be const"GetSpan()SourceModuleId());
296     }
297     if ((specifiers & Specifiers::unit_test_) != Specifiers::none)
298     {
299         throw Exception("member variable cannot be unit_test"GetSpan()SourceModuleId());
300     }
301 }
302 
303 void* MemberVariableSymbol::GetDIMemberType(Emitter& emitteruint64_t offsetInBits)
304 {
305     Assert(layoutIndex != -1"invalid layout index");
306     Assert(Parent() && Parent()->IsClassTypeSymbol()"parent class type expected");
307     ClassTypeSymbol* parentClassType = static_cast<ClassTypeSymbol*>(Parent());
308     std::pair<boost::uuids::uuidint32_t> memberVariableId = std::make_pair(parentClassType->TypeId()layoutIndex);
309     void* localDIType = emitter.GetDIMemberType(memberVariableId);
310     if (!localDIType)
311     {
312         uint64_t sizeInBits = GetType()->SizeInBits(emitter);
313         uint32_t alignInBits = GetType()->AlignmentInBits(emitter);
314         void* scope = parentClassType->GetDIType(emitter);
315         localDIType = emitter.CreateDIMemberType(scopeToUtf8(Name())GetSpan()SourceModuleId()sizeInBitsalignInBitsoffsetInBitsGetType()->GetDIType(emitter));
316         emitter.SetDIMemberType(memberVariableIdlocalDIType);
317     }
318     return localDIType;
319 }
320 
321 std::std::unique_ptr<sngxml::dom::Element>MemberVariableSymbol::CreateDomElement(TypeMap&typeMap)
322 {
323     std::unique_ptr<sngxml::dom::Element> element(new sngxml::dom::Element(U"MemberVariableSymbol"));
324     if (GetType())
325     {
326         std::unique_ptr<sngxml::dom::Element> typeElement(new sngxml::dom::Element(U"type"));
327         int typeId = typeMap.GetOrInsertType(GetType());
328         typeElement->SetAttribute(U"ref"U"type_" + ToUtf32(std::to_string(typeId)));
329         element->AppendChild(std::unique_ptr<sngxml::dom::Node>(typeElement.release()));
330     }
331     return element;
332 }
333 
334 void MemberVariableSymbol::Check()
335 {
336     VariableSymbol::Check();
337     if (layoutIndex == -1)
338     {
339         throw SymbolCheckException("member variable symbol contains invalid layout index"GetSpan()SourceModuleId());
340     }
341 }
342 
343 GlobalVariableGroupSymbol::GlobalVariableGroupSymbol(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) :
344     Symbol(SymbolType::globalVariableGroupSymbolspan_sourceModuleId_name_)
345 {
346 }
347 
348 void GlobalVariableGroupSymbol::ComputeMangledName()
349 {
350     std::u32string mangledName = ToUtf32(TypeString());
351     mangledName.append(1U'_').append(ToUtf32(GetSha1MessageDigest(ToUtf8(FullNameWithSpecifiers()))));
352     SetMangledName(mangledName);
353 }
354 
355 void GlobalVariableGroupSymbol::AddGlobalVariable(GlobalVariableSymbol* globalVariableSymbol)
356 {
357     std::pair<GlobalVariableSymbol*std::string> key(globalVariableSymbolglobalVariableSymbol->CompileUnitFilePath());
358     if (globalVariableSymbols.empty())
359     {
360         globalVariableSymbols.push_back(key);
361         globalVariableSymbol->SetGlobalVariableGroup(this);
362     }
363     else
364     {
365         for (const std::std::pair<GlobalVariableSymbol*std::string>&p : globalVariableSymbols)
366         {
367             if (p.first->Access() == SymbolAccess::internal_ || p.first->Access() == SymbolAccess::public_)
368             {
369                 if (globalVariableSymbol->Access() == SymbolAccess::internal_ || globalVariableSymbol->Access() == SymbolAccess::public_)
370                 {
371                     throw Exception("global variable group '" + ToUtf8(Name()) + 
372                         "' already has public or internal global variable with the given name defined in the source file " + p.second
373                         globalVariableSymbol->GetSpan()globalVariableSymbol->SourceModuleId()GetSpan()SourceModuleId());
374                 }
375             }
376             else
377             {
378                 if (p.second == globalVariableSymbol->CompileUnitFilePath())
379                 {
380                     throw Exception("global variable group '" + ToUtf8(Name()) + "' already has global variable with the given name and compile unit"
381                         globalVariableSymbol->GetSpan()globalVariableSymbol->SourceModuleId()GetSpan()SourceModuleId());
382                 }
383             }
384         }
385         std::vector<std::std::pair<GlobalVariableSymbol*std::string>>::const_iteratorit=std::find(globalVariableSymbols.cbegin()globalVariableSymbols.cend()key);
386         if (it == globalVariableSymbols.cend())
387         {
388             globalVariableSymbols.push_back(key);
389             globalVariableSymbol->SetGlobalVariableGroup(this);
390         }
391         else
392         {
393             throw Exception("global variable group '" + ToUtf8(Name()) + "' already has global variable with the given name and compile unit"
394                 globalVariableSymbol->GetSpan()globalVariableSymbol->SourceModuleId()GetSpan()SourceModuleId());
395         }
396     }
397 }
398 
399 void GlobalVariableGroupSymbol::RemoveGlobalVariable(GlobalVariableSymbol* globalVariableSymbol)
400 {
401     std::pair<GlobalVariableSymbol*std::string> key(globalVariableSymbolglobalVariableSymbol->CompileUnitFilePath());
402     auto end = std::remove(globalVariableSymbols.begin()globalVariableSymbols.end()key);
403     globalVariableSymbols.erase(endglobalVariableSymbols.end());
404 }
405 
406 bool GlobalVariableGroupSymbol::IsEmpty() const
407 {
408     return globalVariableSymbols.empty();
409 }
410 
411 void GlobalVariableGroupSymbol::CollectGlobalVariables(const std::string& compileUnitFilePathstd::std::vector<GlobalVariableSymbol*>&globalVariables) const
412 {
413     for (const std::std::pair<GlobalVariableSymbol*std::string>&p : globalVariableSymbols)
414     {
415         if (p.second == compileUnitFilePath)
416         {
417             globalVariables.push_back(p.first);
418             return;
419         }
420     }
421     for (const std::std::pair<GlobalVariableSymbol*std::string>&p : globalVariableSymbols)
422     {
423         if (p.first->Access() == SymbolAccess::public_ || p.first->Access() == SymbolAccess::internal_)
424         {
425             globalVariables.push_back(p.first);
426             return;
427         }
428     }
429     for (const std::std::pair<GlobalVariableSymbol*std::string>&p : globalVariableSymbols)
430     {
431         globalVariables.push_back(p.first);
432     }
433 }
434 
435 const ContainerScope* GlobalVariableGroupSymbol::GetTypeScope() const
436 {
437     for (const std::std::pair<GlobalVariableSymbol*std::string>&p : globalVariableSymbols)
438     {
439         return p.first->GetTypeScope();
440     }
441     return nullptr;
442 }
443 
444 ContainerScope* GlobalVariableGroupSymbol::GetTypeScope()
445 {
446     for (const std::std::pair<GlobalVariableSymbol*std::string>&p : globalVariableSymbols)
447     {
448         return p.first->GetTypeScope();
449     }
450     return nullptr;
451 }
452 
453 std::string GlobalVariableGroupSymbol::GetSymbolHelp() const
454 {
455     if (globalVariableSymbols.size() == 1)
456     {
457         return globalVariableSymbols.front().first->GetSymbolHelp();
458     }
459     std::string help = "(";
460     help.append(GetSymbolCategoryDescription()).append(") ");
461     help.append(ToUtf8(FullName())).append(" (").append(std::to_string(globalVariableSymbols.size())).append(" global variables)");
462     return help;
463 }
464 
465 std::u32string MakeGlobalVariableName(const std::u32string& groupNameconst std::string& compileUnitId)
466 {
467     std::u32string name = groupName;
468     name.append(1'_').append(ToUtf32(compileUnitId));
469     return name;
470 }
471 
472 GlobalVariableSymbol::GlobalVariableSymbol(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& groupName_const std::string& compileUnitIdconst std::string& compileUnitFilePath_) :
473     VariableSymbol(SymbolType::globalVariableSymbolspan_sourceModuleId_MakeGlobalVariableName(groupName_compileUnitId))groupName(groupName_)compileUnitFilePath(compileUnitFilePath_)
474     globalVariableGroup(nullptr)
475 {
476 }
477 
478 GlobalVariableSymbol::GlobalVariableSymbol(const Span& span_const boost::uuids::uuid& sourceModuleId_const std::u32string& name_) :
479     VariableSymbol(SymbolType::globalVariableSymbolspan_sourceModuleId_name_)globalVariableGroup(nullptr)
480 {
481 }
482 
483 void GlobalVariableSymbol::Write(SymbolWriter& writer)
484 {
485     VariableSymbol::Write(writer);
486     writer.GetBinaryWriter().Write(groupName);
487     writer.GetBinaryWriter().Write(compileUnitFilePath);
488     bool hasInitializer = initializer != nullptr;
489     bool privateAccess = Access() == SymbolAccess::private_;
490     writer.GetBinaryWriter().Write(hasInitializer);
491     if (hasInitializer && !privateAccess)
492     {
493         WriteValue(initializer.get()writer.GetBinaryWriter());
494     }
495 }
496 
497 void GlobalVariableSymbol::Read(SymbolReader& reader)
498 {
499     VariableSymbol::Read(reader);
500     groupName = reader.GetBinaryReader().ReadUtf32String();
501     compileUnitFilePath = reader.GetBinaryReader().ReadUtf8String();
502     bool hasInitializer = reader.GetBinaryReader().ReadBool();
503     bool privateAccess = Access() == SymbolAccess::private_;
504     if (hasInitializer && !privateAccess)
505     {
506         initializer = ReadValue(reader.GetBinaryReader()GetSpan()SourceModuleId());
507         initializer->SetType(GetType());
508     }
509 }
510 
511 bool GlobalVariableSymbol::IsExportSymbol() const
512 {
513     return VariableSymbol::IsExportSymbol();
514 }
515 
516 void GlobalVariableSymbol::Accept(SymbolCollector* collector)
517 {
518     if (IsProject() && Access() == SymbolAccess::public_)
519     {
520         collector->AddGlobalVariable(this);
521     }
522 }
523 
524 void GlobalVariableSymbol::Dump(CodeFormatter& formatter)
525 {
526     formatter.WriteLine(ToUtf8(Name()));
527     formatter.WriteLine("group name: " + ToUtf8(groupName));
528     formatter.WriteLine("full name: " + ToUtf8(FullNameWithSpecifiers()));
529     formatter.WriteLine("mangled name: " + ToUtf8(MangledName()));
530     formatter.WriteLine("type: " + ToUtf8(GetType()->FullName()));
531 }
532 
533 std::string GlobalVariableSymbol::Syntax() const
534 {
535     std::string syntax = GetSpecifierStr();
536     if (!syntax.empty())
537     {
538         syntax.append(1' ');
539     }
540     syntax.append(ToUtf8(GetType()->DocName()));
541     syntax.append(1' ');
542     syntax.append(ToUtf8(DocName()));
543     syntax.append(1';');
544     return syntax;
545 }
546 
547 void GlobalVariableSymbol::ComputeMangledName()
548 {
549     std::u32string mangledName = ToUtf32(TypeString());
550     mangledName.append(1U'_').append(Name());
551     SetMangledName(mangledName);
552 }
553 
554 void GlobalVariableSymbol::SetSpecifiers(Specifiers specifiers)
555 {
556     Specifiers accessSpecifiers = specifiers & Specifiers::access_;
557     SetAccess(accessSpecifiers);
558     if ((specifiers & Specifiers::static_) != Specifiers::none)
559     {
560         throw Exception("global variable cannot be static"GetSpan()SourceModuleId());
561     }
562     if ((specifiers & Specifiers::virtual_) != Specifiers::none)
563     {
564         throw Exception("global variable cannot be virtual"GetSpan()SourceModuleId());
565     }
566     if ((specifiers & Specifiers::override_) != Specifiers::none)
567     {
568         throw Exception("global variable cannot be override"GetSpan()SourceModuleId());
569     }
570     if ((specifiers & Specifiers::abstract_) != Specifiers::none)
571     {
572         throw Exception("global variable cannot be abstract"GetSpan()SourceModuleId());
573     }
574     if ((specifiers & Specifiers::inline_) != Specifiers::none)
575     {
576         throw Exception("global variable cannot be inline"GetSpan()SourceModuleId());
577     }
578     if ((specifiers & Specifiers::explicit_) != Specifiers::none)
579     {
580         throw Exception("global variable cannot be explicit"GetSpan()SourceModuleId());
581     }
582     if ((specifiers & Specifiers::external_) != Specifiers::none)
583     {
584         throw Exception("global variable cannot be external"GetSpan()SourceModuleId());
585     }
586     if ((specifiers & Specifiers::suppress_) != Specifiers::none)
587     {
588         throw Exception("global variable cannot be suppressed"GetSpan()SourceModuleId());
589     }
590     if ((specifiers & Specifiers::default_) != Specifiers::none)
591     {
592         throw Exception("global variable cannot be default"GetSpan()SourceModuleId());
593     }
594     if ((specifiers & Specifiers::constexpr_) != Specifiers::none)
595     {
596         throw Exception("global variable cannot be constexpr"GetSpan()SourceModuleId());
597     }
598     if ((specifiers & Specifiers::cdecl_) != Specifiers::none)
599     {
600         throw Exception("global variable cannot be cdecl"GetSpan()SourceModuleId());
601     }
602     if ((specifiers & Specifiers::nothrow_) != Specifiers::none)
603     {
604         throw Exception("global variable cannot be nothrow"GetSpan()SourceModuleId());
605     }
606     if ((specifiers & Specifiers::throw_) != Specifiers::none)
607     {
608         throw Exception("global variable cannot be throw"GetSpan()SourceModuleId());
609     }
610     if ((specifiers & Specifiers::new_) != Specifiers::none)
611     {
612         throw Exception("global variable cannot be new"GetSpan()SourceModuleId());
613     }
614     if ((specifiers & Specifiers::const_) != Specifiers::none)
615     {
616         throw Exception("global variable cannot be const"GetSpan()SourceModuleId());
617     }
618     if ((specifiers & Specifiers::unit_test_) != Specifiers::none)
619     {
620         throw Exception("global variable cannot be unit_test"GetSpan()SourceModuleId());
621     }
622 }
623 
624 void GlobalVariableSymbol::SetInitializer(std::std::unique_ptr<Value>&&initializer_)
625 {
626     initializer = std::move(initializer_);
627 }
628 
629 void* GlobalVariableSymbol::IrObject(Emitter& emitter)
630 {
631     return emitter.GetOrInsertGlobal(ToUtf8(MangledName())GetType()->IrType(emitter));
632 }
633 
634 void GlobalVariableSymbol::CreateIrObject(Emitter& emitter)
635 {
636     void* irObject = IrObject(emitter);
637     void* init = nullptr;
638     if (initializer == nullptr)
639     {
640         init = GetType()->CreateDefaultIrValue(emitter);
641     }
642     else
643     {
644         init = initializer->IrValue(emitter);
645     }
646     emitter.SetInitializer(irObjectinit);
647 }
648 
649 std::std::unique_ptr<Symbol>GlobalVariableSymbol::RemoveFromParent()
650 {
651     std::unique_ptr<Symbol> symbol = VariableSymbol::RemoveFromParent();
652     if (globalVariableGroup)
653     {
654         globalVariableGroup->RemoveGlobalVariable(this);
655         if (globalVariableGroup->IsEmpty())
656         {
657             std::unique_ptr<Symbol> globalVariableGroupSymbol = globalVariableGroup->RemoveFromParent();
658         }
659     }
660     return symbol;
661 }
662 
663 } } // namespace cmajor::symbols