1 |
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp |
2 |
index e77d29bed712..f3d8eb2602a3 100644 |
3 |
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp |
4 |
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp |
5 |
@@ -124,8 +124,18 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, |
6 |
|
7 |
extern "C" LLVMValueRef |
8 |
LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) { |
9 |
+ Module *Mod = unwrap(M); |
10 |
StringRef NameRef(Name, NameLen); |
11 |
- return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty))); |
12 |
+ |
13 |
+ // We don't use Module::getOrInsertGlobal because that returns a Constant*, |
14 |
+ // which may either be the real GlobalVariable*, or a constant bitcast of it |
15 |
+ // if our type doesn't match the original declaration. We always want the |
16 |
+ // GlobalVariable* so we can access linkage, visibility, etc. |
17 |
+ GlobalVariable *GV = Mod->getGlobalVariable(NameRef, true); |
18 |
+ if (!GV) |
19 |
+ GV = new GlobalVariable(*Mod, unwrap(Ty), false, |
20 |
+ GlobalValue::ExternalLinkage, nullptr, NameRef); |
21 |
+ return wrap(GV); |
22 |
} |
23 |
|
24 |
extern "C" LLVMValueRef |
25 |
diff --git a/src/test/ui/statics/issue-91050-1.rs b/src/test/ui/statics/issue-91050-1.rs |
26 |
new file mode 100644 |
27 |
index 000000000000..403a41462ef1 |
28 |
--- /dev/null |
29 |
+++ b/src/test/ui/statics/issue-91050-1.rs |
30 |
@@ -0,0 +1,34 @@ |
31 |
+// build-pass |
32 |
+// compile-flags: --crate-type=rlib --emit=llvm-ir -Cno-prepopulate-passes |
33 |
+ |
34 |
+// This test declares globals by the same name with different types, which |
35 |
+// caused problems because Module::getOrInsertGlobal would return a Constant* |
36 |
+// bitcast instead of a GlobalVariable* that could access linkage/visibility. |
37 |
+// In alt builds with LLVM assertions this would fail: |
38 |
+// |
39 |
+// rustc: /checkout/src/llvm-project/llvm/include/llvm/Support/Casting.h:269: |
40 |
+// typename cast_retty<X, Y *>::ret_type llvm::cast(Y *) [X = llvm::GlobalValue, Y = llvm::Value]: |
41 |
+// Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed. |
42 |
+// |
43 |
+// In regular builds, the bad cast was UB, like "Invalid LLVMRustVisibility value!" |
44 |
+ |
45 |
+pub mod before { |
46 |
+ #[no_mangle] |
47 |
+ pub static GLOBAL1: [u8; 1] = [1]; |
48 |
+} |
49 |
+ |
50 |
+pub mod inner { |
51 |
+ extern "C" { |
52 |
+ pub static GLOBAL1: u8; |
53 |
+ pub static GLOBAL2: u8; |
54 |
+ } |
55 |
+ |
56 |
+ pub fn call() { |
57 |
+ drop(unsafe { (GLOBAL1, GLOBAL2) }); |
58 |
+ } |
59 |
+} |
60 |
+ |
61 |
+pub mod after { |
62 |
+ #[no_mangle] |
63 |
+ pub static GLOBAL2: [u8; 1] = [2]; |
64 |
+} |
65 |
diff --git a/src/test/ui/statics/issue-91050-2.rs b/src/test/ui/statics/issue-91050-2.rs |
66 |
new file mode 100644 |
67 |
index 000000000000..2ff954d15cab |
68 |
--- /dev/null |
69 |
+++ b/src/test/ui/statics/issue-91050-2.rs |
70 |
@@ -0,0 +1,24 @@ |
71 |
+// build-pass |
72 |
+// compile-flags: --crate-type=rlib --emit=llvm-ir -Cno-prepopulate-passes |
73 |
+ |
74 |
+// This is a variant of issue-91050-1.rs -- see there for an explanation. |
75 |
+ |
76 |
+pub mod before { |
77 |
+ extern "C" { |
78 |
+ pub static GLOBAL1: [u8; 1]; |
79 |
+ } |
80 |
+ |
81 |
+ pub unsafe fn do_something_with_array() -> u8 { |
82 |
+ GLOBAL1[0] |
83 |
+ } |
84 |
+} |
85 |
+ |
86 |
+pub mod inner { |
87 |
+ extern "C" { |
88 |
+ pub static GLOBAL1: u8; |
89 |
+ } |
90 |
+ |
91 |
+ pub unsafe fn call() -> u8 { |
92 |
+ GLOBAL1 + 42 |
93 |
+ } |
94 |
+} |