about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs38
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs10
-rw-r--r--compiler/rustc_expand/src/config.rs54
-rw-r--r--compiler/rustc_target/src/spec/illumos_base.rs11
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs98
-rw-r--r--library/std/src/sys/sgx/abi/tls/mod.rs (renamed from library/std/src/sys/sgx/abi/tls.rs)0
-rw-r--r--library/std/src/sys/sgx/mutex.rs2
-rw-r--r--library/std/src/sys/sgx/waitqueue/mod.rs (renamed from library/std/src/sys/sgx/waitqueue.rs)7
-rw-r--r--library/std/src/sys/sgx/waitqueue/spin_mutex.rs3
-rw-r--r--library/std/src/sys/sgx/waitqueue/unsafe_list.rs3
-rw-r--r--library/std/src/sys/unsupported/args.rs1
-rw-r--r--library/std/src/sys/wasm/args.rs42
-rw-r--r--library/std/src/sys/wasm/atomics/condvar.rs (renamed from library/std/src/sys/wasm/condvar_atomics.rs)0
-rw-r--r--library/std/src/sys/wasm/atomics/futex.rs (renamed from library/std/src/sys/wasm/futex_atomics.rs)0
-rw-r--r--library/std/src/sys/wasm/atomics/mutex.rs (renamed from library/std/src/sys/wasm/mutex_atomics.rs)0
-rw-r--r--library/std/src/sys/wasm/atomics/rwlock.rs (renamed from library/std/src/sys/wasm/rwlock_atomics.rs)0
-rw-r--r--library/std/src/sys/wasm/atomics/thread.rs (renamed from library/std/src/sys/wasm/thread.rs)22
-rw-r--r--library/std/src/sys/wasm/mod.rs14
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/clean/types.rs54
-rw-r--r--src/librustdoc/doctest.rs2
-rw-r--r--src/librustdoc/html/render/context.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs2
-rw-r--r--src/test/rustdoc-ui/invalid-cfg.rs4
-rw-r--r--src/test/rustdoc-ui/invalid-cfg.stderr14
-rw-r--r--src/test/rustdoc/doc-cfg.rs8
-rw-r--r--src/test/ui/target-feature/rust-specific-name-no-warnings.rs5
31 files changed, 199 insertions, 211 deletions
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index b44553e4f6d..6101b90aea6 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -339,24 +339,32 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
         Some(_) | None => {}
     };
 
+    let filter = |s: &str| {
+        if s.is_empty() {
+            return None;
+        }
+        let feature = if s.starts_with("+") || s.starts_with("-") {
+            &s[1..]
+        } else {
+            return Some(s.to_string());
+        };
+        // Rustc-specific feature requests like `+crt-static` or `-crt-static`
+        // are not passed down to LLVM.
+        if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+            return None;
+        }
+        // ... otherwise though we run through `to_llvm_feature` feature when
+        // passing requests down to LLVM. This means that all in-language
+        // features also work on the command line instead of having two
+        // different names when the LLVM name and the Rust name differ.
+        Some(format!("{}{}", &s[..1], to_llvm_feature(sess, feature)))
+    };
+
     // Features implied by an implicit or explicit `--target`.
-    features.extend(
-        sess.target
-            .features
-            .split(',')
-            .filter(|f| !f.is_empty() && !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)))
-            .map(String::from),
-    );
+    features.extend(sess.target.features.split(',').filter_map(&filter));
 
     // -Ctarget-features
-    features.extend(
-        sess.opts
-            .cg
-            .target_feature
-            .split(',')
-            .filter(|f| !f.is_empty() && !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)))
-            .map(String::from),
-    );
+    features.extend(sess.opts.cg.target_feature.split(',').filter_map(&filter));
 
     features
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 401d379b0d1..929bdf22755 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -340,6 +340,14 @@ impl<'a> Linker for GccLinker<'a> {
     }
 
     fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
+        if self.sess.target.os == "illumos" && lib.as_str() == "c" {
+            // libc will be added via late_link_args on illumos so that it will
+            // appear last in the library search order.
+            // FIXME: This should be replaced by a more complete and generic
+            // mechanism for controlling the order of library arguments passed
+            // to the linker.
+            return;
+        }
         if !as_needed {
             if self.sess.target.is_like_osx {
                 // FIXME(81490): ld64 doesn't support these flags but macOS 11
@@ -813,11 +821,9 @@ impl<'a> Linker for MsvcLinker<'a> {
     }
 
     fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
-        self.link_staticlib(lib, verbatim);
         self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
     fn link_whole_rlib(&mut self, path: &Path) {
-        self.link_rlib(path);
         let mut arg = OsString::from("/WHOLEARCHIVE:");
         arg.push(path);
         self.cmd.arg(arg);
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 03c83f9c07b..f9140609c0f 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -464,31 +464,9 @@ impl<'a> StripUnconfigured<'a> {
                     return true;
                 }
             };
-            let error = |span, msg, suggestion: &str| {
-                let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
-                if !suggestion.is_empty() {
-                    err.span_suggestion(
-                        span,
-                        "expected syntax is",
-                        suggestion.into(),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                err.emit();
-                true
-            };
-            let span = meta_item.span;
-            match meta_item.meta_item_list() {
-                None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
-                Some([]) => error(span, "`cfg` predicate is not specified", ""),
-                Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
-                Some([single]) => match single.meta_item() {
-                    Some(meta_item) => {
-                        attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features)
-                    }
-                    None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
-                },
-            }
+            parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
+                attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
+            })
         })
     }
 
@@ -532,6 +510,32 @@ impl<'a> StripUnconfigured<'a> {
     }
 }
 
+pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> {
+    let error = |span, msg, suggestion: &str| {
+        let mut err = sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
+        if !suggestion.is_empty() {
+            err.span_suggestion(
+                span,
+                "expected syntax is",
+                suggestion.into(),
+                Applicability::HasPlaceholders,
+            );
+        }
+        err.emit();
+        None
+    };
+    let span = meta_item.span;
+    match meta_item.meta_item_list() {
+        None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"),
+        Some([]) => error(span, "`cfg` predicate is not specified", ""),
+        Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
+        Some([single]) => match single.meta_item() {
+            Some(meta_item) => Some(meta_item),
+            None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
+        },
+    }
+}
+
 fn is_cfg(sess: &Session, attr: &Attribute) -> bool {
     sess.check_name(attr, sym::cfg)
 }
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index 2e365d210f3..2b8e046c46b 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -6,6 +6,17 @@ pub fn opts() -> TargetOptions {
     late_link_args.insert(
         LinkerFlavor::Gcc,
         vec![
+            // The illumos libc contains a stack unwinding implementation, as
+            // does libgcc_s.  The latter implementation includes several
+            // additional symbols that are not always in base libc.  To force
+            // the consistent use of just one unwinder, we ensure libc appears
+            // after libgcc_s in the NEEDED list for the resultant binary by
+            // ignoring any attempts to add it as a dynamic dependency until the
+            // very end.
+            // FIXME: This should be replaced by a more complete and generic
+            // mechanism for controlling the order of library arguments passed
+            // to the linker.
+            "-lc".to_string(),
             // LLVM will insert calls to the stack protector functions
             // "__stack_chk_fail" and "__stack_chk_guard" into code in native
             // object files.  Some platforms include these symbols directly in
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs
index 28d9801b78c..359cb0f6881 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_none_hermitkernel.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
     base.stack_probes = StackProbeType::Call;
 
     Target {
-        llvm_target: "x86_64-unknown-none-elf".to_string(),
+        llvm_target: "x86_64-unknown-hermit".to_string(),
         pointer_width: 64,
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 0c6a33b91ce..4d6caf07236 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -720,11 +720,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn select_obligations_where_possible(
         &self,
         fallback_has_occurred: bool,
-        mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
+        mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
     ) {
         let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
         if let Err(mut errors) = result {
-            mutate_fullfillment_errors(&mut errors);
+            mutate_fulfillment_errors(&mut errors);
             self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
         }
     }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 80b5a9d4e62..3417bc01972 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -986,7 +986,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             error.obligation.predicate.kind().skip_binder()
                         {
                             // If any of the type arguments in this path segment caused the
-                            // `FullfillmentError`, point at its span (#61860).
+                            // `FulfillmentError`, point at its span (#61860).
                             for arg in path
                                 .segments
                                 .iter()
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 4914f196afb..7436edccf84 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -43,7 +43,7 @@ struct CheckWfFcxBuilder<'tcx> {
 impl<'tcx> CheckWfFcxBuilder<'tcx> {
     fn with_fcx<F>(&mut self, f: F)
     where
-        F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>, TyCtxt<'tcx>) -> Vec<Ty<'tcx>>,
+        F: for<'b> FnOnce(&FnCtxt<'b, 'tcx>) -> Vec<Ty<'tcx>>,
     {
         let id = self.id;
         let span = self.span;
@@ -56,7 +56,7 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> {
                 // empty `param_env`.
                 check_false_global_bounds(&fcx, span, id);
             }
-            let wf_tys = f(&fcx, fcx.tcx);
+            let wf_tys = f(&fcx);
             fcx.select_all_obligations_or_error();
             fcx.regionck_item(id, span, &wf_tys);
         });
@@ -388,7 +388,7 @@ fn check_associated_item(
     debug!("check_associated_item: {:?}", item_id);
 
     let code = ObligationCauseCode::MiscObligation;
-    for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
+    for_id(tcx, item_id, span).with_fcx(|fcx| {
         let item = fcx.tcx.associated_item(fcx.tcx.hir().local_def_id(item_id));
 
         let (mut implied_bounds, self_ty) = match item.container {
@@ -409,7 +409,6 @@ fn check_associated_item(
                 let sig = fcx.normalize_associated_types_in(span, sig);
                 let hir_sig = sig_if_method.expect("bad signature for method");
                 check_fn_or_method(
-                    tcx,
                     fcx,
                     item.ident.span,
                     sig,
@@ -467,9 +466,9 @@ fn check_type_defn<'tcx, F>(
 ) where
     F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec<AdtVariant<'tcx>>,
 {
-    for_item(tcx, item).with_fcx(|fcx, fcx_tcx| {
+    for_item(tcx, item).with_fcx(|fcx| {
         let variants = lookup_fields(fcx);
-        let packed = fcx.tcx.adt_def(item.def_id).repr.packed();
+        let packed = tcx.adt_def(item.def_id).repr.packed();
 
         for variant in &variants {
             // For DST, or when drop needs to copy things around, all
@@ -477,15 +476,14 @@ fn check_type_defn<'tcx, F>(
             let needs_drop_copy = || {
                 packed && {
                     let ty = variant.fields.last().unwrap().ty;
-                    let ty = fcx.tcx.erase_regions(ty);
+                    let ty = tcx.erase_regions(ty);
                     if ty.needs_infer() {
-                        fcx_tcx
-                            .sess
+                        tcx.sess
                             .delay_span_bug(item.span, &format!("inference variables in {:?}", ty));
                         // Just treat unresolved type expression as if it needs drop.
                         true
                     } else {
-                        ty.needs_drop(fcx_tcx, fcx_tcx.param_env(item.def_id))
+                        ty.needs_drop(tcx, tcx.param_env(item.def_id))
                     }
                 }
             };
@@ -497,7 +495,7 @@ fn check_type_defn<'tcx, F>(
                 let last = idx == variant.fields.len() - 1;
                 fcx.register_bound(
                     field.ty,
-                    fcx.tcx.require_lang_item(LangItem::Sized, None),
+                    tcx.require_lang_item(LangItem::Sized, None),
                     traits::ObligationCause::new(
                         field.span,
                         fcx.body_id,
@@ -524,11 +522,10 @@ fn check_type_defn<'tcx, F>(
 
             // Explicit `enum` discriminant values must const-evaluate successfully.
             if let Some(discr_def_id) = variant.explicit_discr {
-                let discr_substs =
-                    InternalSubsts::identity_for_item(fcx.tcx, discr_def_id.to_def_id());
+                let discr_substs = InternalSubsts::identity_for_item(tcx, discr_def_id.to_def_id());
 
                 let cause = traits::ObligationCause::new(
-                    fcx.tcx.def_span(discr_def_id),
+                    tcx.def_span(discr_def_id),
                     fcx.body_id,
                     traits::MiscObligation,
                 );
@@ -539,12 +536,12 @@ fn check_type_defn<'tcx, F>(
                         ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
                         discr_substs,
                     )
-                    .to_predicate(fcx.tcx),
+                    .to_predicate(tcx),
                 ));
             }
         }
 
-        check_where_clauses(tcx, fcx, item.span, item.def_id.to_def_id(), None);
+        check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None);
 
         // No implied bounds in a struct definition.
         vec![]
@@ -569,8 +566,9 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
         }
     }
 
-    for_item(tcx, item).with_fcx(|fcx, _| {
-        check_where_clauses(tcx, fcx, item.span, item.def_id.to_def_id(), None);
+    // FIXME: this shouldn't use an `FnCtxt` at all.
+    for_item(tcx, item).with_fcx(|fcx| {
+        check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None);
 
         vec![]
     });
@@ -610,20 +608,12 @@ fn check_item_fn(
     span: Span,
     decl: &hir::FnDecl<'_>,
 ) {
-    for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
-        let def_id = fcx.tcx.hir().local_def_id(item_id);
-        let sig = fcx.tcx.fn_sig(def_id);
+    for_id(tcx, item_id, span).with_fcx(|fcx| {
+        let def_id = tcx.hir().local_def_id(item_id);
+        let sig = tcx.fn_sig(def_id);
         let sig = fcx.normalize_associated_types_in(span, sig);
         let mut implied_bounds = vec![];
-        check_fn_or_method(
-            tcx,
-            fcx,
-            ident.span,
-            sig,
-            decl,
-            def_id.to_def_id(),
-            &mut implied_bounds,
-        );
+        check_fn_or_method(fcx, ident.span, sig, decl, def_id.to_def_id(), &mut implied_bounds);
         implied_bounds
     })
 }
@@ -631,7 +621,7 @@ fn check_item_fn(
 fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_foreign_ty: bool) {
     debug!("check_item_type: {:?}", item_id);
 
-    for_id(tcx, item_id, ty_span).with_fcx(|fcx, tcx| {
+    for_id(tcx, item_id, ty_span).with_fcx(|fcx| {
         let ty = tcx.type_of(tcx.hir().local_def_id(item_id));
         let item_ty = fcx.normalize_associated_types_in(ty_span, ty);
 
@@ -647,7 +637,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo
         if forbid_unsized {
             fcx.register_bound(
                 item_ty,
-                fcx.tcx.require_lang_item(LangItem::Sized, None),
+                tcx.require_lang_item(LangItem::Sized, None),
                 traits::ObligationCause::new(ty_span, fcx.body_id, traits::MiscObligation),
             );
         }
@@ -665,13 +655,13 @@ fn check_impl<'tcx>(
 ) {
     debug!("check_impl: {:?}", item);
 
-    for_item(tcx, item).with_fcx(|fcx, tcx| {
+    for_item(tcx, item).with_fcx(|fcx| {
         match *ast_trait_ref {
             Some(ref ast_trait_ref) => {
                 // `#[rustc_reservation_impl]` impls are not real impls and
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
-                let trait_ref = fcx.tcx.impl_trait_ref(item.def_id).unwrap();
+                let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap();
                 let trait_ref =
                     fcx.normalize_associated_types_in(ast_trait_ref.path.span, trait_ref);
                 let obligations = traits::wf::trait_obligations(
@@ -687,7 +677,7 @@ fn check_impl<'tcx>(
                 }
             }
             None => {
-                let self_ty = fcx.tcx.type_of(item.def_id);
+                let self_ty = tcx.type_of(item.def_id);
                 let self_ty = fcx.normalize_associated_types_in(item.span, self_ty);
                 fcx.register_wf_obligation(
                     self_ty.into(),
@@ -697,7 +687,7 @@ fn check_impl<'tcx>(
             }
         }
 
-        check_where_clauses(tcx, fcx, item.span, item.def_id.to_def_id(), None);
+        check_where_clauses(fcx, item.span, item.def_id.to_def_id(), None);
 
         fcx.impl_implied_bounds(item.def_id.to_def_id(), item.span)
     });
@@ -705,15 +695,15 @@ fn check_impl<'tcx>(
 
 /// Checks where-clauses and inline bounds that are declared on `def_id`.
 fn check_where_clauses<'tcx, 'fcx>(
-    tcx: TyCtxt<'tcx>,
     fcx: &FnCtxt<'fcx, 'tcx>,
     span: Span,
     def_id: DefId,
     return_ty: Option<(Ty<'tcx>, Span)>,
 ) {
     debug!("check_where_clauses(def_id={:?}, return_ty={:?})", def_id, return_ty);
+    let tcx = fcx.tcx;
 
-    let predicates = fcx.tcx.predicates_of(def_id);
+    let predicates = tcx.predicates_of(def_id);
     let generics = tcx.generics_of(def_id);
 
     let is_our_default = |def: &ty::GenericParamDef| match def.kind {
@@ -734,14 +724,14 @@ fn check_where_clauses<'tcx, 'fcx>(
         match param.kind {
             GenericParamDefKind::Type { .. } => {
                 if is_our_default(&param) {
-                    let ty = fcx.tcx.type_of(param.def_id);
+                    let ty = tcx.type_of(param.def_id);
                     // Ignore dependent defaults -- that is, where the default of one type
                     // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
                     // be sure if it will error or not as user might always specify the other.
                     if !ty.needs_subst() {
                         fcx.register_wf_obligation(
                             ty.into(),
-                            fcx.tcx.def_span(param.def_id),
+                            tcx.def_span(param.def_id),
                             ObligationCauseCode::MiscObligation,
                         );
                     }
@@ -754,7 +744,7 @@ fn check_where_clauses<'tcx, 'fcx>(
                     let default_ct = tcx.const_param_default(param.def_id);
                     fcx.register_wf_obligation(
                         default_ct.into(),
-                        fcx.tcx.def_span(param.def_id),
+                        tcx.def_span(param.def_id),
                         ObligationCauseCode::MiscObligation,
                     );
                 }
@@ -772,17 +762,17 @@ fn check_where_clauses<'tcx, 'fcx>(
     // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
     //
     // First we build the defaulted substitution.
-    let substs = InternalSubsts::for_item(fcx.tcx, def_id, |param, _| {
+    let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
         match param.kind {
             GenericParamDefKind::Lifetime => {
                 // All regions are identity.
-                fcx.tcx.mk_param_from_def(param)
+                tcx.mk_param_from_def(param)
             }
 
             GenericParamDefKind::Type { .. } => {
                 // If the param has a default, ...
                 if is_our_default(param) {
-                    let default_ty = fcx.tcx.type_of(param.def_id);
+                    let default_ty = tcx.type_of(param.def_id);
                     // ... and it's not a dependent default, ...
                     if !default_ty.needs_subst() {
                         // ... then substitute it with the default.
@@ -790,7 +780,7 @@ fn check_where_clauses<'tcx, 'fcx>(
                     }
                 }
 
-                fcx.tcx.mk_param_from_def(param)
+                tcx.mk_param_from_def(param)
             }
             GenericParamDefKind::Const { .. } => {
                 // FIXME(const_generics_defaults): I(@lcnr) feel like always
@@ -811,7 +801,7 @@ fn check_where_clauses<'tcx, 'fcx>(
                     }
                 }
 
-                fcx.tcx.mk_param_from_def(param)
+                tcx.mk_param_from_def(param)
             }
         }
     });
@@ -848,7 +838,7 @@ fn check_where_clauses<'tcx, 'fcx>(
             }
             let mut param_count = CountParams::default();
             let has_region = pred.visit_with(&mut param_count).is_break();
-            let substituted_pred = pred.subst(fcx.tcx, substs);
+            let substituted_pred = pred.subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
             if substituted_pred.has_param_types_or_consts()
@@ -879,14 +869,14 @@ fn check_where_clauses<'tcx, 'fcx>(
             traits::Obligation::new(cause, fcx.param_env, pred)
         });
 
-    let predicates = predicates.instantiate_identity(fcx.tcx);
+    let predicates = predicates.instantiate_identity(tcx);
 
     if let Some((mut return_ty, span)) = return_ty {
         if return_ty.has_infer_types_or_consts() {
             fcx.select_obligations_where_possible(false, |_| {});
             return_ty = fcx.resolve_vars_if_possible(return_ty);
         }
-        check_opaque_types(tcx, fcx, def_id.expect_local(), span, return_ty);
+        check_opaque_types(fcx, def_id.expect_local(), span, return_ty);
     }
 
     let predicates = fcx.normalize_associated_types_in(span, predicates);
@@ -905,7 +895,6 @@ fn check_where_clauses<'tcx, 'fcx>(
 }
 
 fn check_fn_or_method<'fcx, 'tcx>(
-    tcx: TyCtxt<'tcx>,
     fcx: &FnCtxt<'fcx, 'tcx>,
     span: Span,
     sig: ty::PolyFnSig<'tcx>,
@@ -930,7 +919,7 @@ fn check_fn_or_method<'fcx, 'tcx>(
     // FIXME(#25759) return types should not be implied bounds
     implied_bounds.push(sig.output());
 
-    check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
+    check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
 }
 
 /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
@@ -953,15 +942,16 @@ fn check_fn_or_method<'fcx, 'tcx>(
 /// ```
 ///
 fn check_opaque_types<'fcx, 'tcx>(
-    tcx: TyCtxt<'tcx>,
     fcx: &FnCtxt<'fcx, 'tcx>,
     fn_def_id: LocalDefId,
     span: Span,
     ty: Ty<'tcx>,
 ) {
-    trace!("check_opaque_types(ty={:?})", ty);
+    trace!("check_opaque_types(fn_def_id={:?}, ty={:?})", fn_def_id, ty);
+    let tcx = fcx.tcx;
+
     ty.fold_with(&mut ty::fold::BottomUpFolder {
-        tcx: fcx.tcx,
+        tcx,
         ty_op: |ty| {
             if let ty::Opaque(def_id, substs) = *ty.kind() {
                 trace!("check_opaque_types: opaque_ty, {:?}, {:?}", def_id, substs);
diff --git a/library/std/src/sys/sgx/abi/tls.rs b/library/std/src/sys/sgx/abi/tls/mod.rs
index 13d96e9a633..13d96e9a633 100644
--- a/library/std/src/sys/sgx/abi/tls.rs
+++ b/library/std/src/sys/sgx/abi/tls/mod.rs
diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs
index 8874517dac6..1b5ced4178f 100644
--- a/library/std/src/sys/sgx/mutex.rs
+++ b/library/std/src/sys/sgx/mutex.rs
@@ -8,7 +8,7 @@ pub struct Mutex {
     inner: SpinMutex<WaitVariable<bool>>,
 }
 
-pub type MovableMutex = Box<Mutex>;
+pub type MovableMutex = Mutex;
 
 // Implementation according to “Operating Systems: Three Easy Pieces”, chapter 28
 impl Mutex {
diff --git a/library/std/src/sys/sgx/waitqueue.rs b/library/std/src/sys/sgx/waitqueue/mod.rs
index e464dc3ee9d..61bb11d9a6f 100644
--- a/library/std/src/sys/sgx/waitqueue.rs
+++ b/library/std/src/sys/sgx/waitqueue/mod.rs
@@ -13,13 +13,8 @@
 #[cfg(test)]
 mod tests;
 
-/// A doubly-linked list where callers are in charge of memory allocation
-/// of the nodes in the list.
-mod unsafe_list;
-
-/// Trivial spinlock-based implementation of `sync::Mutex`.
-// FIXME: Perhaps use Intel TSX to avoid locking?
 mod spin_mutex;
+mod unsafe_list;
 
 use crate::num::NonZeroUsize;
 use crate::ops::{Deref, DerefMut};
diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs
index 7f1a671bab4..f6e851ccadd 100644
--- a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs
+++ b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs
@@ -1,3 +1,6 @@
+//! Trivial spinlock-based implementation of `sync::Mutex`.
+// FIXME: Perhaps use Intel TSX to avoid locking?
+
 #[cfg(test)]
 mod tests;
 
diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
index 0834d2593fc..cf2f0886c15 100644
--- a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
+++ b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
@@ -1,3 +1,6 @@
+//! A doubly-linked list where callers are in charge of memory allocation
+//! of the nodes in the list.
+
 #[cfg(test)]
 mod tests;
 
diff --git a/library/std/src/sys/unsupported/args.rs b/library/std/src/sys/unsupported/args.rs
index c924a7d8a26..a2d75a61976 100644
--- a/library/std/src/sys/unsupported/args.rs
+++ b/library/std/src/sys/unsupported/args.rs
@@ -1,4 +1,5 @@
 use crate::ffi::OsString;
+use crate::fmt;
 
 pub struct Args {}
 
diff --git a/library/std/src/sys/wasm/args.rs b/library/std/src/sys/wasm/args.rs
deleted file mode 100644
index fde1ab79e1f..00000000000
--- a/library/std/src/sys/wasm/args.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use crate::ffi::OsString;
-use crate::fmt;
-use crate::vec;
-
-pub fn args() -> Args {
-    Args { iter: Vec::new().into_iter() }
-}
-
-pub struct Args {
-    iter: vec::IntoIter<OsString>,
-}
-
-impl !Send for Args {}
-impl !Sync for Args {}
-
-impl fmt::Debug for Args {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.iter.as_slice().fmt(f)
-    }
-}
-
-impl Iterator for Args {
-    type Item = OsString;
-    fn next(&mut self) -> Option<OsString> {
-        self.iter.next()
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        self.iter.size_hint()
-    }
-}
-
-impl ExactSizeIterator for Args {
-    fn len(&self) -> usize {
-        self.iter.len()
-    }
-}
-
-impl DoubleEndedIterator for Args {
-    fn next_back(&mut self) -> Option<OsString> {
-        self.iter.next_back()
-    }
-}
diff --git a/library/std/src/sys/wasm/condvar_atomics.rs b/library/std/src/sys/wasm/atomics/condvar.rs
index 0c1c076cc91..0c1c076cc91 100644
--- a/library/std/src/sys/wasm/condvar_atomics.rs
+++ b/library/std/src/sys/wasm/atomics/condvar.rs
diff --git a/library/std/src/sys/wasm/futex_atomics.rs b/library/std/src/sys/wasm/atomics/futex.rs
index 3d8bf42f725..3d8bf42f725 100644
--- a/library/std/src/sys/wasm/futex_atomics.rs
+++ b/library/std/src/sys/wasm/atomics/futex.rs
diff --git a/library/std/src/sys/wasm/mutex_atomics.rs b/library/std/src/sys/wasm/atomics/mutex.rs
index 5ff0ec052b6..5ff0ec052b6 100644
--- a/library/std/src/sys/wasm/mutex_atomics.rs
+++ b/library/std/src/sys/wasm/atomics/mutex.rs
diff --git a/library/std/src/sys/wasm/rwlock_atomics.rs b/library/std/src/sys/wasm/atomics/rwlock.rs
index 06442e925f4..06442e925f4 100644
--- a/library/std/src/sys/wasm/rwlock_atomics.rs
+++ b/library/std/src/sys/wasm/atomics/rwlock.rs
diff --git a/library/std/src/sys/wasm/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs
index b7bf95c89b4..54bc877aa7d 100644
--- a/library/std/src/sys/wasm/thread.rs
+++ b/library/std/src/sys/wasm/atomics/thread.rs
@@ -13,20 +13,10 @@ impl Thread {
         unsupported()
     }
 
-    pub fn yield_now() {
-        // do nothing
-    }
+    pub fn yield_now() {}
 
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
+    pub fn set_name(_name: &CStr) {}
 
-    #[cfg(not(target_feature = "atomics"))]
-    pub fn sleep(_dur: Duration) {
-        panic!("can't sleep");
-    }
-
-    #[cfg(target_feature = "atomics")]
     pub fn sleep(dur: Duration) {
         use crate::arch::wasm32;
         use crate::cmp;
@@ -46,9 +36,7 @@ impl Thread {
         }
     }
 
-    pub fn join(self) {
-        self.0
-    }
+    pub fn join(self) {}
 }
 
 pub mod guard {
@@ -61,11 +49,9 @@ pub mod guard {
     }
 }
 
-// This is only used by atomics primitives when the `atomics` feature is
-// enabled. In that mode we currently just use our own thread-local to store our
+// We currently just use our own thread-local to store our
 // current thread's ID, and then we lazily initialize it to something allocated
 // from a global counter.
-#[cfg(target_feature = "atomics")]
 pub fn my_id() -> u32 {
     use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};
 
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index afcc5ca9286..cd701a333f8 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -17,6 +17,7 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
 pub mod alloc;
+#[path = "../unsupported/args.rs"]
 pub mod args;
 #[path = "../unix/cmath.rs"]
 pub mod cmath;
@@ -37,7 +38,6 @@ pub mod pipe;
 pub mod process;
 #[path = "../unsupported/stdio.rs"]
 pub mod stdio;
-pub mod thread;
 #[path = "../unsupported/thread_local_dtor.rs"]
 pub mod thread_local_dtor;
 #[path = "../unsupported/thread_local_key.rs"]
@@ -49,14 +49,16 @@ pub use crate::sys_common::os_str_bytes as os_str;
 
 cfg_if::cfg_if! {
     if #[cfg(target_feature = "atomics")] {
-        #[path = "condvar_atomics.rs"]
+        #[path = "atomics/condvar.rs"]
         pub mod condvar;
-        #[path = "mutex_atomics.rs"]
+        #[path = "atomics/mutex.rs"]
         pub mod mutex;
-        #[path = "rwlock_atomics.rs"]
+        #[path = "atomics/rwlock.rs"]
         pub mod rwlock;
-        #[path = "futex_atomics.rs"]
+        #[path = "atomics/futex.rs"]
         pub mod futex;
+        #[path = "atomics/thread.rs"]
+        pub mod thread;
     } else {
         #[path = "../unsupported/condvar.rs"]
         pub mod condvar;
@@ -64,6 +66,8 @@ cfg_if::cfg_if! {
         pub mod mutex;
         #[path = "../unsupported/rwlock.rs"]
         pub mod rwlock;
+        #[path = "../unsupported/thread.rs"]
+        pub mod thread;
     }
 }
 
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 5974cd878dd..6d05ac073cc 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -317,10 +317,10 @@ fn merge_attrs(
             } else {
                 Attributes::from_ast(&both, None)
             },
-            both.cfg(cx.sess().diagnostic()),
+            both.cfg(cx.sess()),
         )
     } else {
-        (old_attrs.clean(cx), old_attrs.cfg(cx.sess().diagnostic()))
+        (old_attrs.clean(cx), old_attrs.cfg(cx.sess()))
     }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 411cfab9f06..e1dde8eeaf8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2018,7 +2018,7 @@ fn clean_extern_crate(
         def_id: crate_def_id.into(),
         visibility: krate.vis.clean(cx),
         kind: box ExternCrateItem { src: orig_name },
-        cfg: attrs.cfg(cx.sess().diagnostic()),
+        cfg: attrs.cfg(cx.sess()),
     }]
 }
 
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 47dae63f1fd..9861e838e33 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -444,7 +444,7 @@ impl Item {
             kind,
             box ast_attrs.clean(cx),
             cx,
-            ast_attrs.cfg(cx.sess().diagnostic()),
+            ast_attrs.cfg(cx.sess()),
         )
     }
 
@@ -456,7 +456,7 @@ impl Item {
         cx: &mut DocContext<'_>,
         cfg: Option<Arc<Cfg>>,
     ) -> Item {
-        debug!("name={:?}, def_id={:?}", name, def_id);
+        trace!("name={:?}, def_id={:?}", name, def_id);
 
         Item {
             def_id: def_id.into(),
@@ -795,7 +795,7 @@ crate trait AttributesExt {
 
     fn other_attrs(&self) -> Vec<ast::Attribute>;
 
-    fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option<Arc<Cfg>>;
+    fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>>;
 }
 
 impl AttributesExt for [ast::Attribute] {
@@ -820,17 +820,28 @@ impl AttributesExt for [ast::Attribute] {
         self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect()
     }
 
-    fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option<Arc<Cfg>> {
+    fn cfg(&self, sess: &Session) -> Option<Arc<Cfg>> {
         let mut cfg = Cfg::True;
 
         for attr in self.iter() {
+            // #[doc]
             if attr.doc_str().is_none() && attr.has_name(sym::doc) {
-                if let Some(mi) = attr.meta() {
-                    if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
-                        // Extracted #[doc(cfg(...))]
-                        match Cfg::parse(cfg_mi) {
-                            Ok(new_cfg) => cfg &= new_cfg,
-                            Err(e) => diagnostic.span_err(e.span, e.msg),
+                // #[doc(...)]
+                if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) {
+                    for item in list {
+                        // #[doc(include)]
+                        if !item.has_name(sym::cfg) {
+                            continue;
+                        }
+                        // #[doc(cfg(...))]
+                        if let Some(cfg_mi) = item
+                            .meta_item()
+                            .and_then(|item| rustc_expand::config::parse_cfg(&item, sess))
+                        {
+                            match Cfg::parse(&cfg_mi) {
+                                Ok(new_cfg) => cfg &= new_cfg,
+                                Err(e) => sess.span_err(e.span, e.msg),
+                            }
                         }
                     }
                 }
@@ -997,29 +1008,6 @@ impl Attributes {
         self.other_attrs.lists(name)
     }
 
-    /// Extracts the content from an attribute `#[doc(cfg(content))]`.
-    crate fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> {
-        use rustc_ast::NestedMetaItem::MetaItem;
-
-        if let ast::MetaItemKind::List(ref nmis) = mi.kind {
-            if nmis.len() == 1 {
-                if let MetaItem(ref cfg_mi) = nmis[0] {
-                    if cfg_mi.has_name(sym::cfg) {
-                        if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind {
-                            if cfg_nmis.len() == 1 {
-                                if let MetaItem(ref content_mi) = cfg_nmis[0] {
-                                    return Some(content_mi);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        None
-    }
-
     /// Reads a `MetaItem` from within an attribute, looks for whether it is a
     /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from
     /// its expansion.
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index c0157121e19..e563889f776 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1096,7 +1096,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
         let ast_attrs = self.tcx.hir().attrs(hir_id);
         let mut attrs = Attributes::from_ast(ast_attrs, None);
 
-        if let Some(ref cfg) = ast_attrs.cfg(self.sess.diagnostic()) {
+        if let Some(ref cfg) = ast_attrs.cfg(self.sess) {
             if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
                 return;
             }
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 2f3f87215c3..e0c1fd06e7b 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -155,7 +155,7 @@ impl<'tcx> Context<'tcx> {
         &self.cache
     }
 
-    fn sess(&self) -> &'tcx Session {
+    pub(super) fn sess(&self) -> &'tcx Session {
         &self.shared.tcx.sess
     }
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 70b5458ece8..9d4ac3cf015 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -296,7 +296,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                     let import_item = clean::Item {
                         def_id: import_def_id.into(),
                         attrs: import_attrs,
-                        cfg: ast_attrs.cfg(cx.tcx().sess.diagnostic()),
+                        cfg: ast_attrs.cfg(cx.sess()),
                         ..myitem.clone()
                     };
 
diff --git a/src/test/rustdoc-ui/invalid-cfg.rs b/src/test/rustdoc-ui/invalid-cfg.rs
new file mode 100644
index 00000000000..d237b8605c0
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-cfg.rs
@@ -0,0 +1,4 @@
+#![feature(doc_cfg)]
+#[doc(cfg = "x")] //~ ERROR not followed by parentheses
+#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates
+struct S {}
diff --git a/src/test/rustdoc-ui/invalid-cfg.stderr b/src/test/rustdoc-ui/invalid-cfg.stderr
new file mode 100644
index 00000000000..dae238b052b
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-cfg.stderr
@@ -0,0 +1,14 @@
+error: `cfg` is not followed by parentheses
+  --> $DIR/invalid-cfg.rs:2:7
+   |
+LL | #[doc(cfg = "x")]
+   |       ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)`
+
+error: multiple `cfg` predicates are specified
+  --> $DIR/invalid-cfg.rs:3:14
+   |
+LL | #[doc(cfg(x, y))]
+   |              ^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs
index 89a61a289fd..1fc80b3e76c 100644
--- a/src/test/rustdoc/doc-cfg.rs
+++ b/src/test/rustdoc/doc-cfg.rs
@@ -91,3 +91,11 @@ pub unsafe fn uses_target_feature() {
 pub fn uses_cfg_target_feature() {
     uses_target_feature();
 }
+
+// multiple attributes should be allowed
+// @has doc_cfg/fn.multiple_attrs.html \
+//  '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \
+//  'This is supported on x and y and z only.'
+#[doc(inline, cfg(x))]
+#[doc(cfg(y), cfg(z))]
+pub fn multiple_attrs() {}
diff --git a/src/test/ui/target-feature/rust-specific-name-no-warnings.rs b/src/test/ui/target-feature/rust-specific-name-no-warnings.rs
new file mode 100644
index 00000000000..1708a71a981
--- /dev/null
+++ b/src/test/ui/target-feature/rust-specific-name-no-warnings.rs
@@ -0,0 +1,5 @@
+// build-pass
+// only-x86
+// compile-flags: -C target-feature=+pclmulqdq
+
+fn main() {}