]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
Auto merge of #107185 - compiler-errors:rollup-wkomjma, r=compiler-errors
[rust.git] / compiler / rustc_llvm / llvm-wrapper / ArchiveWrapper.cpp
1 #include "LLVMWrapper.h"
2
3 #include "llvm/Object/Archive.h"
4 #include "llvm/Object/ArchiveWriter.h"
5 #include "llvm/Support/Path.h"
6
7 using namespace llvm;
8 using namespace llvm::object;
9
10 struct RustArchiveMember {
11   const char *Filename;
12   const char *Name;
13   Archive::Child Child;
14
15   RustArchiveMember()
16       : Filename(nullptr), Name(nullptr),
17         Child(nullptr, nullptr, nullptr)
18   {
19   }
20   ~RustArchiveMember() {}
21 };
22
23 struct RustArchiveIterator {
24   bool First;
25   Archive::child_iterator Cur;
26   Archive::child_iterator End;
27   std::unique_ptr<Error> Err;
28
29   RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End,
30       std::unique_ptr<Error> Err)
31     : First(true),
32       Cur(Cur),
33       End(End),
34       Err(std::move(Err)) {}
35 };
36
37 enum class LLVMRustArchiveKind {
38   GNU,
39   BSD,
40   DARWIN,
41   COFF,
42 };
43
44 static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
45   switch (Kind) {
46   case LLVMRustArchiveKind::GNU:
47     return Archive::K_GNU;
48   case LLVMRustArchiveKind::BSD:
49     return Archive::K_BSD;
50   case LLVMRustArchiveKind::DARWIN:
51     return Archive::K_DARWIN;
52   case LLVMRustArchiveKind::COFF:
53     return Archive::K_COFF;
54   default:
55     report_fatal_error("Bad ArchiveKind.");
56   }
57 }
58
59 typedef OwningBinary<Archive> *LLVMRustArchiveRef;
60 typedef RustArchiveMember *LLVMRustArchiveMemberRef;
61 typedef Archive::Child *LLVMRustArchiveChildRef;
62 typedef Archive::Child const *LLVMRustArchiveChildConstRef;
63 typedef RustArchiveIterator *LLVMRustArchiveIteratorRef;
64
65 extern "C" LLVMRustArchiveRef LLVMRustOpenArchive(char *Path) {
66   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOr =
67       MemoryBuffer::getFile(Path, -1, false);
68   if (!BufOr) {
69     LLVMRustSetLastError(BufOr.getError().message().c_str());
70     return nullptr;
71   }
72
73   Expected<std::unique_ptr<Archive>> ArchiveOr =
74       Archive::create(BufOr.get()->getMemBufferRef());
75
76   if (!ArchiveOr) {
77     LLVMRustSetLastError(toString(ArchiveOr.takeError()).c_str());
78     return nullptr;
79   }
80
81   OwningBinary<Archive> *Ret = new OwningBinary<Archive>(
82       std::move(ArchiveOr.get()), std::move(BufOr.get()));
83
84   return Ret;
85 }
86
87 extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) {
88   delete RustArchive;
89 }
90
91 extern "C" LLVMRustArchiveIteratorRef
92 LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) {
93   Archive *Archive = RustArchive->getBinary();
94   std::unique_ptr<Error> Err = std::make_unique<Error>(Error::success());
95   auto Cur = Archive->child_begin(*Err);
96   if (*Err) {
97     LLVMRustSetLastError(toString(std::move(*Err)).c_str());
98     return nullptr;
99   }
100   auto End = Archive->child_end();
101   return new RustArchiveIterator(Cur, End, std::move(Err));
102 }
103
104 extern "C" LLVMRustArchiveChildConstRef
105 LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) {
106   if (RAI->Cur == RAI->End)
107     return nullptr;
108
109   // Advancing the iterator validates the next child, and this can
110   // uncover an error. LLVM requires that we check all Errors,
111   // so we only advance the iterator if we actually need to fetch
112   // the next child.
113   // This means we must not advance the iterator in the *first* call,
114   // but instead advance it *before* fetching the child in all later calls.
115   if (!RAI->First) {
116     ++RAI->Cur;
117     if (*RAI->Err) {
118       LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str());
119       return nullptr;
120     }
121   } else {
122     RAI->First = false;
123   }
124
125   if (RAI->Cur == RAI->End)
126     return nullptr;
127
128   const Archive::Child &Child = *RAI->Cur.operator->();
129   Archive::Child *Ret = new Archive::Child(Child);
130
131   return Ret;
132 }
133
134 extern "C" void LLVMRustArchiveChildFree(LLVMRustArchiveChildRef Child) {
135   delete Child;
136 }
137
138 extern "C" void LLVMRustArchiveIteratorFree(LLVMRustArchiveIteratorRef RAI) {
139   delete RAI;
140 }
141
142 extern "C" const char *
143 LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
144   Expected<StringRef> NameOrErr = Child->getName();
145   if (!NameOrErr) {
146     // rustc_codegen_llvm currently doesn't use this error string, but it might be
147     // useful in the future, and in the mean time this tells LLVM that the
148     // error was not ignored and that it shouldn't abort the process.
149     LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
150     return nullptr;
151   }
152   StringRef Name = NameOrErr.get();
153   *Size = Name.size();
154   return Name.data();
155 }
156
157 extern "C" LLVMRustArchiveMemberRef
158 LLVMRustArchiveMemberNew(char *Filename, char *Name,
159                          LLVMRustArchiveChildRef Child) {
160   RustArchiveMember *Member = new RustArchiveMember;
161   Member->Filename = Filename;
162   Member->Name = Name;
163   if (Child)
164     Member->Child = *Child;
165   return Member;
166 }
167
168 extern "C" void LLVMRustArchiveMemberFree(LLVMRustArchiveMemberRef Member) {
169   delete Member;
170 }
171
172 extern "C" LLVMRustResult
173 LLVMRustWriteArchive(char *Dst, size_t NumMembers,
174                      const LLVMRustArchiveMemberRef *NewMembers,
175                      bool WriteSymbtab, LLVMRustArchiveKind RustKind) {
176
177   std::vector<NewArchiveMember> Members;
178   auto Kind = fromRust(RustKind);
179
180   for (size_t I = 0; I < NumMembers; I++) {
181     auto Member = NewMembers[I];
182     assert(Member->Name);
183     if (Member->Filename) {
184       Expected<NewArchiveMember> MOrErr =
185           NewArchiveMember::getFile(Member->Filename, true);
186       if (!MOrErr) {
187         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
188         return LLVMRustResult::Failure;
189       }
190       MOrErr->MemberName = sys::path::filename(MOrErr->MemberName);
191       Members.push_back(std::move(*MOrErr));
192     } else {
193       Expected<NewArchiveMember> MOrErr =
194           NewArchiveMember::getOldMember(Member->Child, true);
195       if (!MOrErr) {
196         LLVMRustSetLastError(toString(MOrErr.takeError()).c_str());
197         return LLVMRustResult::Failure;
198       }
199       Members.push_back(std::move(*MOrErr));
200     }
201   }
202
203   auto Result = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
204   if (!Result)
205     return LLVMRustResult::Success;
206   LLVMRustSetLastError(toString(std::move(Result)).c_str());
207
208   return LLVMRustResult::Failure;
209 }