File tree Expand file tree Collapse file tree 4 files changed +43
-0
lines changed Expand file tree Collapse file tree 4 files changed +43
-0
lines changed Original file line number Diff line number Diff line change @@ -1913,3 +1913,6 @@ extern fn ZigClangLoadFromCommandLine(
19131913 errors_len : * usize ,
19141914 resources_path : [* :0 ]const u8 ,
19151915) ? * ASTUnit ;
1916+
1917+ pub const isLLVMUsingSeparateLibcxx = ZigClangIsLLVMUsingSeparateLibcxx ;
1918+ extern fn ZigClangIsLLVMUsingSeparateLibcxx () bool ;
Original file line number Diff line number Diff line change @@ -175,6 +175,15 @@ pub fn main() anyerror!void {
175175}
176176
177177pub fn mainArgs (gpa : Allocator , arena : Allocator , args : []const []const u8 ) ! void {
178+ if (build_options .have_llvm ) {
179+ if (ZigClangIsLLVMUsingSeparateLibcxx ()) {
180+ fatal (
181+ \\Zig was built/linked incorrectly: LLVM and Clang have separate copies of libc++
182+ \\ If you are dynamically linking LLVM, make sure you dynamically link libc++ too
183+ , .{});
184+ }
185+ }
186+
178187 if (args .len <= 1 ) {
179188 std .log .info ("{s}" , .{usage });
180189 fatal ("expected command argument" , .{});
@@ -4457,6 +4466,8 @@ pub const info_zen =
44574466 \\
44584467;
44594468
4469+ extern fn ZigClangIsLLVMUsingSeparateLibcxx () bool ;
4470+
44604471extern "c" fn ZigClang_main (argc : c_int , argv : [* :null ]? [* :0 ]u8 ) c_int ;
44614472extern "c" fn ZigLlvmAr_main (argc : c_int , argv : [* :null ]? [* :0 ]u8 ) c_int ;
44624473
Original file line number Diff line number Diff line change @@ -3432,3 +3432,31 @@ const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct Zi
34323432 const llvm::APSInt *result = &casted->getInitVal ();
34333433 return reinterpret_cast <const ZigClangAPSInt *>(result);
34343434}
3435+
3436+ // Get a pointer to a static variable in libc++ from LLVM and make sure that
3437+ // it matches our own.
3438+ //
3439+ // This check is needed because if static/dynamic linking is mixed incorrectly,
3440+ // it's possible for Clang and LLVM to end up with duplicate "copies" of libc++.
3441+ //
3442+ // This is not benign: Static variables are not shared, so equality comparisons
3443+ // that depend on pointers to static variables will fail. One such failure is
3444+ // std::generic_category(), which causes POSIX error codes to compare as unequal
3445+ // when passed between LLVM and Clang.
3446+ //
3447+ // See also: https://github.com/ziglang/zig/issues/11168
3448+ bool ZigClangIsLLVMUsingSeparateLibcxx () {
3449+
3450+ // Temporarily create an InMemoryFileSystem, so that we can perform a file
3451+ // lookup that is guaranteed to fail.
3452+ auto FS = new llvm::vfs::InMemoryFileSystem (true );
3453+ auto StatusOrErr = FS->status (" foo.txt" );
3454+ delete FS;
3455+
3456+ // This should return a POSIX (generic_category) error code, but if LLVM has
3457+ // its own copy of libc++ this will actually be a separate category instance.
3458+ assert (!StatusOrErr);
3459+ auto EC = StatusOrErr.getError ();
3460+ return EC.category () != std::generic_category ();
3461+ }
3462+
Original file line number Diff line number Diff line change @@ -1418,4 +1418,5 @@ ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const
14181418ZIG_EXTERN_C unsigned ZigClangFieldDecl_getFieldIndex (const struct ZigClangFieldDecl * );
14191419
14201420ZIG_EXTERN_C const struct ZigClangAPSInt * ZigClangEnumConstantDecl_getInitVal (const struct ZigClangEnumConstantDecl * );
1421+ ZIG_EXTERN_C bool ZigClangIsLLVMUsingSeparateLibcxx ();
14211422#endif
You can’t perform that action at this time.
0 commit comments