|
| 1 | +#[cfg(feature="master")] |
| 2 | +use gccjit::{FnAttribute, Visibility}; |
1 | 3 | use gccjit::{FunctionType, RValue};
|
2 | 4 | use rustc_codegen_ssa::traits::BaseTypeMethods;
|
3 | 5 | use rustc_middle::ty::{self, Instance, TypeFoldable};
|
@@ -70,8 +72,97 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>)
|
70 | 72 |
|
71 | 73 | attributes::from_fn_attrs(cx, func, instance);
|
72 | 74 |
|
| 75 | + let instance_def_id = instance.def_id(); |
| 76 | + |
73 | 77 | // TODO(antoyo): set linkage and attributes.
|
74 | 78 |
|
| 79 | + // Apply an appropriate linkage/visibility value to our item that we |
| 80 | + // just declared. |
| 81 | + // |
| 82 | + // This is sort of subtle. Inside our codegen unit we started off |
| 83 | + // compilation by predefining all our own `MonoItem` instances. That |
| 84 | + // is, everything we're codegenning ourselves is already defined. That |
| 85 | + // means that anything we're actually codegenning in this codegen unit |
| 86 | + // will have hit the above branch in `get_declared_value`. As a result, |
| 87 | + // we're guaranteed here that we're declaring a symbol that won't get |
| 88 | + // defined, or in other words we're referencing a value from another |
| 89 | + // codegen unit or even another crate. |
| 90 | + // |
| 91 | + // So because this is a foreign value we blanket apply an external |
| 92 | + // linkage directive because it's coming from a different object file. |
| 93 | + // The visibility here is where it gets tricky. This symbol could be |
| 94 | + // referencing some foreign crate or foreign library (an `extern` |
| 95 | + // block) in which case we want to leave the default visibility. We may |
| 96 | + // also, though, have multiple codegen units. It could be a |
| 97 | + // monomorphization, in which case its expected visibility depends on |
| 98 | + // whether we are sharing generics or not. The important thing here is |
| 99 | + // that the visibility we apply to the declaration is the same one that |
| 100 | + // has been applied to the definition (wherever that definition may be). |
| 101 | + let is_generic = instance.substs.non_erasable_generics().next().is_some(); |
| 102 | + |
| 103 | + if is_generic { |
| 104 | + // This is a monomorphization. Its expected visibility depends |
| 105 | + // on whether we are in share-generics mode. |
| 106 | + |
| 107 | + if cx.tcx.sess.opts.share_generics() { |
| 108 | + // We are in share_generics mode. |
| 109 | + |
| 110 | + if let Some(instance_def_id) = instance_def_id.as_local() { |
| 111 | + // This is a definition from the current crate. If the |
| 112 | + // definition is unreachable for downstream crates or |
| 113 | + // the current crate does not re-export generics, the |
| 114 | + // definition of the instance will have been declared |
| 115 | + // as `hidden`. |
| 116 | + if cx.tcx.is_unreachable_local_definition(instance_def_id) |
| 117 | + || !cx.tcx.local_crate_exports_generics() |
| 118 | + { |
| 119 | + #[cfg(feature="master")] |
| 120 | + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); |
| 121 | + } |
| 122 | + } else { |
| 123 | + // This is a monomorphization of a generic function |
| 124 | + // defined in an upstream crate. |
| 125 | + if instance.upstream_monomorphization(tcx).is_some() { |
| 126 | + // This is instantiated in another crate. It cannot |
| 127 | + // be `hidden`. |
| 128 | + } else { |
| 129 | + // This is a local instantiation of an upstream definition. |
| 130 | + // If the current crate does not re-export it |
| 131 | + // (because it is a C library or an executable), it |
| 132 | + // will have been declared `hidden`. |
| 133 | + if !cx.tcx.local_crate_exports_generics() { |
| 134 | + #[cfg(feature="master")] |
| 135 | + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + } else { |
| 140 | + // When not sharing generics, all instances are in the same |
| 141 | + // crate and have hidden visibility |
| 142 | + #[cfg(feature="master")] |
| 143 | + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); |
| 144 | + } |
| 145 | + } else { |
| 146 | + // This is a non-generic function |
| 147 | + if cx.tcx.is_codegened_item(instance_def_id) { |
| 148 | + // This is a function that is instantiated in the local crate |
| 149 | + |
| 150 | + if instance_def_id.is_local() { |
| 151 | + // This is function that is defined in the local crate. |
| 152 | + // If it is not reachable, it is hidden. |
| 153 | + if !cx.tcx.is_reachable_non_generic(instance_def_id) { |
| 154 | + #[cfg(feature="master")] |
| 155 | + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); |
| 156 | + } |
| 157 | + } else { |
| 158 | + // This is a function from an upstream crate that has |
| 159 | + // been instantiated here. These are always hidden. |
| 160 | + #[cfg(feature="master")] |
| 161 | + func.add_attribute(FnAttribute::Visibility(Visibility::Hidden)); |
| 162 | + } |
| 163 | + } |
| 164 | + } |
| 165 | + |
75 | 166 | // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
|
76 | 167 | unsafe { std::mem::transmute(func) }
|
77 | 168 | };
|
|
0 commit comments