about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs35
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs66
2 files changed, 88 insertions, 13 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 9fef31acef8..24aeb024461 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -166,21 +166,42 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
         return;
     }
 
-    // For the wasm32 target statics with `#[link_section]` are placed into custom
-    // sections of the final output file, but this isn't link custom sections of
-    // other executable formats. Namely we can only embed a list of bytes,
-    // nothing with provenance (pointers to anything else). If any provenance
-    // show up, reject it here.
+    // For the wasm32 target statics with `#[link_section]` other than `.init_array`
+    // are placed into custom sections of the final output file, but this isn't like
+    // custom sections of other executable formats. Namely we can only embed a list
+    // of bytes, nothing with provenance (pointers to anything else). If any
+    // provenance show up, reject it here.
     // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
     // the consumer's responsibility to ensure all bytes that have been read
     // have defined values.
+    //
+    // The `.init_array` section is left to go through the normal custom section code path.
+    // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests
+    // in workarounds in user-code.
+    //
+    //   * The linker fails to merge multiple items in a crate into the .init_array section.
+    //     To work around this, a single array can be used placing multiple items in the array.
+    //     #[link_section = ".init_array"]
+    //     static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];
+    //   * Even symbols marked used get gc'd from dependant crates unless at least one symbol
+    //     in the crate is marked with an `#[export_name]`
+    //
+    //  Once `.init_array` support in wasm-ld is complete, the user code workarounds should
+    //  continue to work, but would no longer be necessary.
+
     if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
         && alloc.inner().provenance().ptrs().len() != 0
     {
-        let msg = "statics with a custom `#[link_section]` must be a \
+        if attrs
+            .link_section
+            .map(|link_section| !link_section.as_str().starts_with(".init_array"))
+            .unwrap()
+        {
+            let msg = "statics with a custom `#[link_section]` must be a \
                         simple list of bytes on the wasm target with no \
                         extra levels of indirection such as references";
-        tcx.dcx().span_err(tcx.def_span(id), msg);
+            tcx.dcx().span_err(tcx.def_span(id), msg);
+        }
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 7b8a03def86..7d1ab232c71 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -1087,7 +1087,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     );
 
                     let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT");
-                    if let Some(suggested_name) = find_best_match_for_name(
+                    if let Some(variant_name) = find_best_match_for_name(
                         &adt_def
                             .variants()
                             .iter()
@@ -1095,12 +1095,66 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             .collect::<Vec<Symbol>>(),
                         assoc_ident.name,
                         None,
-                    ) {
-                        err.span_suggestion(
-                            assoc_ident.span,
+                    ) && let Some(variant) =
+                        adt_def.variants().iter().find(|s| s.name == variant_name)
+                    {
+                        let mut suggestion = vec![(assoc_ident.span, variant_name.to_string())];
+                        if let hir::Node::Stmt(hir::Stmt {
+                            kind: hir::StmtKind::Semi(ref expr),
+                            ..
+                        })
+                        | hir::Node::Expr(ref expr) = tcx.parent_hir_node(hir_ref_id)
+                            && let hir::ExprKind::Struct(..) = expr.kind
+                        {
+                            match variant.ctor {
+                                None => {
+                                    // struct
+                                    suggestion = vec![(
+                                        assoc_ident.span.with_hi(expr.span.hi()),
+                                        if variant.fields.is_empty() {
+                                            format!("{variant_name} {{}}")
+                                        } else {
+                                            format!(
+                                                "{variant_name} {{ {} }}",
+                                                variant
+                                                    .fields
+                                                    .iter()
+                                                    .map(|f| format!("{}: /* value */", f.name))
+                                                    .collect::<Vec<_>>()
+                                                    .join(", ")
+                                            )
+                                        },
+                                    )];
+                                }
+                                Some((hir::def::CtorKind::Fn, def_id)) => {
+                                    // tuple
+                                    let fn_sig = tcx.fn_sig(def_id).instantiate_identity();
+                                    let inputs = fn_sig.inputs().skip_binder();
+                                    suggestion = vec![(
+                                        assoc_ident.span.with_hi(expr.span.hi()),
+                                        format!(
+                                            "{variant_name}({})",
+                                            inputs
+                                                .iter()
+                                                .map(|i| format!("/* {i} */"))
+                                                .collect::<Vec<_>>()
+                                                .join(", ")
+                                        ),
+                                    )];
+                                }
+                                Some((hir::def::CtorKind::Const, _)) => {
+                                    // unit
+                                    suggestion = vec![(
+                                        assoc_ident.span.with_hi(expr.span.hi()),
+                                        variant_name.to_string(),
+                                    )];
+                                }
+                            }
+                        }
+                        err.multipart_suggestion_verbose(
                             "there is a variant with a similar name",
-                            suggested_name,
-                            Applicability::MaybeIncorrect,
+                            suggestion,
+                            Applicability::HasPlaceholders,
                         );
                     } else {
                         err.span_label(