about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_hir_analysis/locales/en-US.ftl8
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs133
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs22
-rw-r--r--compiler/rustc_lint/src/context.rs17
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs7
-rw-r--r--compiler/rustc_middle/src/query/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs4
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs135
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs8
-rw-r--r--compiler/rustc_resolve/src/lib.rs9
-rw-r--r--library/core/src/lib.rs4
-rw-r--r--library/core/src/net/display_buffer.rs (renamed from library/std/src/net/display_buffer.rs)0
-rw-r--r--library/core/src/net/ip_addr.rs2070
-rw-r--r--library/core/src/net/mod.rs24
-rw-r--r--library/core/src/net/parser.rs (renamed from library/std/src/net/parser.rs)4
-rw-r--r--library/core/src/net/socket_addr.rs664
-rw-r--r--library/core/tests/lib.rs5
-rw-r--r--library/core/tests/net/ip_addr.rs1035
-rw-r--r--library/core/tests/net/mod.rs13
-rw-r--r--library/core/tests/net/parser.rs (renamed from library/std/src/net/parser/tests.rs)4
-rw-r--r--library/core/tests/net/socket_addr.rs233
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/net/ip_addr.rs2075
-rw-r--r--library/std/src/net/ip_addr/tests.rs1035
-rw-r--r--library/std/src/net/mod.rs6
-rw-r--r--library/std/src/net/socket_addr.rs689
-rw-r--r--library/std/src/sys/windows/c.rs32
-rw-r--r--library/std/src/sys/windows/stdio.rs74
-rw-r--r--src/bootstrap/Cargo.lock4
-rw-r--r--src/bootstrap/Cargo.toml5
-rw-r--r--src/bootstrap/compile.rs2
-rw-r--r--src/bootstrap/config.rs1
-rw-r--r--src/bootstrap/format.rs2
-rw-r--r--src/bootstrap/metadata.rs2
-rw-r--r--src/bootstrap/metrics.rs2
-rw-r--r--src/bootstrap/toolstate.rs2
-rw-r--r--tests/ui/resolve/issue-108529.rs8
-rw-r--r--tests/ui/resolve/issue-108529.stderr9
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.fixed10
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.rs10
-rw-r--r--tests/ui/rust-2018/remove-extern-crate.stderr22
-rw-r--r--tests/ui/traits/issue-77982.stderr2
-rw-r--r--tests/ui/traits/new-solver/try-example.rs28
-rw-r--r--tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs24
-rw-r--r--tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr14
50 files changed, 4449 insertions, 4024 deletions
diff --git a/README.md b/README.md
index 0eb7c4b266a..c424bd12ffd 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 # The Rust Programming Language
 
+[![Rust Community](https://img.shields.io/badge/Rust_Community%20-Join_us-brightgreen?style=plastic&logo=rust)](https://www.rust-lang.org/community)
+
 This is the main source code repository for [Rust]. It contains the compiler,
 standard library, and documentation.
 
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 926b0da2ec6..96042ea3078 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -386,7 +386,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ).span_suggestion_verbose(
                 lhs.span.shrink_to_lo(),
                 "you might have meant to introduce a new binding",
-                "let ".to_string(),
+                "let ",
                 Applicability::MachineApplicable,
             ).emit();
         }
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index ea58ad5ae3e..5e4c7292e59 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -467,7 +467,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 err.span_suggestion_verbose(
                     span.shrink_to_lo(),
                     "consider borrowing here",
-                    "&".to_string(),
+                    '&',
                     Applicability::MaybeIncorrect,
                 );
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 9f37b915b77..ef0542b57ad 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -385,7 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     err.span_suggestion_verbose(
                         local_decl.source_info.span.shrink_to_lo(),
                         "consider changing this to be mutable",
-                        "mut ".to_string(),
+                        "mut ",
                         Applicability::MachineApplicable,
                     );
                     let tcx = self.infcx.tcx;
diff --git a/compiler/rustc_hir_analysis/locales/en-US.ftl b/compiler/rustc_hir_analysis/locales/en-US.ftl
index 50b0816889b..40b5bc2a32e 100644
--- a/compiler/rustc_hir_analysis/locales/en-US.ftl
+++ b/compiler/rustc_hir_analysis/locales/en-US.ftl
@@ -62,14 +62,6 @@ hir_analysis_manual_implementation =
 
 hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
 
-hir_analysis_unused_extern_crate =
-    unused extern crate
-    .suggestion = remove it
-
-hir_analysis_extern_crate_not_idiomatic =
-    `extern crate` is not idiomatic in the new edition
-    .suggestion = convert it to a `{$msg_code}`
-
 hir_analysis_trait_object_declared_with_no_traits =
     at least one trait is required for an object type
     .alias_span = this alias does not contain a trait
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 5716be4f1a9..f3f5851d8f9 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -1,12 +1,8 @@
-use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate};
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint;
-use rustc_span::{Span, Symbol};
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let mut used_trait_imports: UnordSet<LocalDefId> = Default::default();
@@ -43,131 +39,4 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
             |lint| lint,
         );
     }
-
-    unused_crates_lint(tcx);
-}
-
-fn unused_crates_lint(tcx: TyCtxt<'_>) {
-    let lint = lint::builtin::UNUSED_EXTERN_CRATES;
-
-    // Collect first the crates that are completely unused. These we
-    // can always suggest removing (no matter which edition we are
-    // in).
-    let unused_extern_crates: FxHashMap<LocalDefId, Span> = tcx
-        .maybe_unused_extern_crates(())
-        .iter()
-        .filter(|&&(def_id, _)| {
-            tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| {
-                !tcx.is_compiler_builtins(cnum)
-                    && !tcx.is_panic_runtime(cnum)
-                    && !tcx.has_global_allocator(cnum)
-                    && !tcx.has_panic_handler(cnum)
-            })
-        })
-        .cloned()
-        .collect();
-
-    // Collect all the extern crates (in a reliable order).
-    let mut crates_to_lint = vec![];
-
-    for id in tcx.hir().items() {
-        if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) {
-            let item = tcx.hir().item(id);
-            if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
-                crates_to_lint.push(ExternCrateToLint {
-                    def_id: item.owner_id.to_def_id(),
-                    span: item.span,
-                    orig_name,
-                    warn_if_unused: !item.ident.as_str().starts_with('_'),
-                });
-            }
-        }
-    }
-
-    let extern_prelude = &tcx.resolutions(()).extern_prelude;
-
-    for extern_crate in &crates_to_lint {
-        let def_id = extern_crate.def_id.expect_local();
-        let item = tcx.hir().expect_item(def_id);
-
-        // If the crate is fully unused, we suggest removing it altogether.
-        // We do this in any edition.
-        if extern_crate.warn_if_unused {
-            if let Some(&span) = unused_extern_crates.get(&def_id) {
-                // Removal suggestion span needs to include attributes (Issue #54400)
-                let id = tcx.hir().local_def_id_to_hir_id(def_id);
-                let span_with_attrs = tcx
-                    .hir()
-                    .attrs(id)
-                    .iter()
-                    .map(|attr| attr.span)
-                    .fold(span, |acc, attr_span| acc.to(attr_span));
-
-                tcx.emit_spanned_lint(lint, id, span, UnusedExternCrate { span: span_with_attrs });
-                continue;
-            }
-        }
-
-        // If we are not in Rust 2018 edition, then we don't make any further
-        // suggestions.
-        if !tcx.sess.rust_2018() {
-            continue;
-        }
-
-        // If the extern crate isn't in the extern prelude,
-        // there is no way it can be written as a `use`.
-        let orig_name = extern_crate.orig_name.unwrap_or(item.ident.name);
-        if !extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) {
-            continue;
-        }
-
-        // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
-        // would not insert the new name into the prelude, where other imports in the crate may be
-        // expecting it.
-        if extern_crate.orig_name.is_some() {
-            continue;
-        }
-
-        let id = tcx.hir().local_def_id_to_hir_id(def_id);
-        // If the extern crate has any attributes, they may have funky
-        // semantics we can't faithfully represent using `use` (most
-        // notably `#[macro_use]`). Ignore it.
-        if !tcx.hir().attrs(id).is_empty() {
-            continue;
-        }
-
-        let base_replacement = match extern_crate.orig_name {
-            Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name),
-            None => format!("use {};", item.ident.name),
-        };
-        let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default();
-        let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) };
-        tcx.emit_spanned_lint(
-            lint,
-            id,
-            extern_crate.span,
-            ExternCrateNotIdiomatic {
-                span: extern_crate.span,
-                msg_code: add_vis("use".to_string()),
-                suggestion_code: add_vis(base_replacement),
-            },
-        );
-    }
-}
-
-struct ExternCrateToLint {
-    /// `DefId` of the extern crate
-    def_id: DefId,
-
-    /// span from the item
-    span: Span,
-
-    /// if `Some`, then this is renamed (`extern crate orig_name as
-    /// crate_name`), and -- perhaps surprisingly -- this stores the
-    /// *original* name (`item.name` will contain the new name)
-    orig_name: Option<Symbol>,
-
-    /// if `false`, the original name started with `_`, so we shouldn't lint
-    /// about it going unused (but we should still emit idiom lints).
-    warn_if_unused: bool,
 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index a566e73912e..203e0f85cad 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -5,7 +5,7 @@ use rustc_errors::{
     error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
     MultiSpan,
 };
-use rustc_macros::{Diagnostic, LintDiagnostic};
+use rustc_macros::Diagnostic;
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
@@ -247,26 +247,6 @@ pub struct SubstsOnOverriddenImpl {
     pub span: Span,
 }
 
-#[derive(LintDiagnostic)]
-#[diag(hir_analysis_unused_extern_crate)]
-pub struct UnusedExternCrate {
-    #[suggestion(applicability = "machine-applicable", code = "")]
-    pub span: Span,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(hir_analysis_extern_crate_not_idiomatic)]
-pub struct ExternCrateNotIdiomatic {
-    #[suggestion(
-        style = "short",
-        applicability = "machine-applicable",
-        code = "{suggestion_code}"
-    )]
-    pub span: Span,
-    pub msg_code: String,
-    pub suggestion_code: String,
-}
-
 #[derive(Diagnostic)]
 #[diag(hir_analysis_const_impl_for_non_const_trait)]
 pub struct ConstImplForNonConstTrait {
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index aace4974cc9..f5a711315ea 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -893,6 +893,23 @@ pub trait LintContext: Sized {
                 BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => {
                     db.help("consider implementing the trait by hand, or remove the `packed` attribute");
                 }
+                BuiltinLintDiagnostics::UnusedExternCrate { removal_span }=> {
+                    db.span_suggestion(
+                        removal_span,
+                        "remove it",
+                        "",
+                        Applicability::MachineApplicable,
+                    );
+                }
+                BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span }=> {
+                    let suggestion_span = vis_span.between(ident_span);
+                    db.span_suggestion_verbose(
+                        suggestion_span,
+                        "convert it to a `use`",
+                        if vis_span.is_empty() { "use " } else { " use " },
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(db)
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 6efbf5ce9ee..534aff7fb62 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -522,6 +522,13 @@ pub enum BuiltinLintDiagnostics {
         is_formatting_arg: bool,
     },
     ByteSliceInPackedStructWithDerive,
+    UnusedExternCrate {
+        removal_span: Span,
+    },
+    ExternCrateNotIdiomatic {
+        vis_span: Span,
+        ident_span: Span,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d4435a54b4a..d37c8d3813b 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1830,9 +1830,6 @@ rustc_queries! {
     query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet<LocalDefId> {
         desc { "fetching potentially unused trait imports" }
     }
-    query maybe_unused_extern_crates(_: ()) -> &'tcx [(LocalDefId, Span)] {
-        desc { "looking up all possibly unused extern crates" }
-    }
     query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxHashSet<Symbol> {
         desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 433c9ab9aa2..0333198c203 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -2487,8 +2487,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
     providers.maybe_unused_trait_imports =
         |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
-    providers.maybe_unused_extern_crates =
-        |tcx, ()| &tcx.resolutions(()).maybe_unused_extern_crates[..];
     providers.names_imported_by_glob_use = |tcx, id| {
         tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
     };
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 17262a0be24..c3e9dc7bcc1 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -165,12 +165,8 @@ pub struct ResolverGlobalCtxt {
     pub effective_visibilities: EffectiveVisibilities,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
-    pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
     pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
     pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
-    /// Extern prelude entries. The value is `true` if the entry was introduced
-    /// via `extern crate` item and not `--extern` option or compiler built-in.
-    pub extern_prelude: FxHashMap<Symbol, bool>,
     pub main_def: Option<MainDefinition>,
     pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
     /// A list of proc macro LocalDefIds, written out in the order in which
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 0114e116386..b2578e4c4b4 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -29,11 +29,12 @@ use crate::Resolver;
 
 use rustc_ast as ast;
 use rustc_ast::visit::{self, Visitor};
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{pluralize, MultiSpan};
-use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_IMPORTS};
+use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS};
 use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
 struct UnusedImport<'a> {
@@ -53,11 +54,28 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     r: &'a mut Resolver<'b, 'tcx>,
     /// All the (so far) unused imports, grouped path list
     unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>,
+    extern_crate_items: Vec<ExternCrateToLint>,
     base_use_tree: Option<&'a ast::UseTree>,
     base_id: ast::NodeId,
     item_span: Span,
 }
 
+struct ExternCrateToLint {
+    id: ast::NodeId,
+    /// Span from the item
+    span: Span,
+    /// Span to use to suggest complete removal.
+    span_with_attributes: Span,
+    /// Span of the visibility, if any.
+    vis_span: Span,
+    /// Whether the item has attrs.
+    has_attrs: bool,
+    /// Name used to refer to the crate.
+    ident: Ident,
+    /// Whether the statement renames the crate `extern crate orig_name as new_name;`.
+    renames: bool,
+}
+
 impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     // We have information about whether `use` (import) items are actually
     // used now. If an import is not used at all, we signal a lint error.
@@ -96,18 +114,27 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
 
 impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     fn visit_item(&mut self, item: &'a ast::Item) {
-        self.item_span = item.span_with_attributes();
-
-        // Ignore is_public import statements because there's no way to be sure
-        // whether they're used or not. Also ignore imports with a dummy span
-        // because this means that they were generated in some fashion by the
-        // compiler and we don't need to consider them.
-        if let ast::ItemKind::Use(..) = item.kind {
-            if item.vis.kind.is_pub() || item.span.is_dummy() {
-                return;
+        match item.kind {
+            // Ignore is_public import statements because there's no way to be sure
+            // whether they're used or not. Also ignore imports with a dummy span
+            // because this means that they were generated in some fashion by the
+            // compiler and we don't need to consider them.
+            ast::ItemKind::Use(..) if item.vis.kind.is_pub() || item.span.is_dummy() => return,
+            ast::ItemKind::ExternCrate(orig_name) => {
+                self.extern_crate_items.push(ExternCrateToLint {
+                    id: item.id,
+                    span: item.span,
+                    vis_span: item.vis.span,
+                    span_with_attributes: item.span_with_attributes(),
+                    has_attrs: !item.attrs.is_empty(),
+                    ident: item.ident,
+                    renames: orig_name.is_some(),
+                });
             }
+            _ => {}
         }
 
+        self.item_span = item.span_with_attributes();
         visit::walk_item(self, item);
     }
 
@@ -224,6 +251,9 @@ fn calc_unused_spans(
 
 impl Resolver<'_, '_> {
     pub(crate) fn check_unused(&mut self, krate: &ast::Crate) {
+        let tcx = self.tcx;
+        let mut maybe_unused_extern_crates = FxHashMap::default();
+
         for import in self.potentially_unused_imports.iter() {
             match import.kind {
                 _ if import.used.get()
@@ -246,7 +276,14 @@ impl Resolver<'_, '_> {
                 }
                 ImportKind::ExternCrate { id, .. } => {
                     let def_id = self.local_def_id(id);
-                    self.maybe_unused_extern_crates.push((def_id, import.span));
+                    if self.extern_crate_map.get(&def_id).map_or(true, |&cnum| {
+                        !tcx.is_compiler_builtins(cnum)
+                            && !tcx.is_panic_runtime(cnum)
+                            && !tcx.has_global_allocator(cnum)
+                            && !tcx.has_panic_handler(cnum)
+                    }) {
+                        maybe_unused_extern_crates.insert(id, import.span);
+                    }
                 }
                 ImportKind::MacroUse => {
                     let msg = "unused `#[macro_use]` import";
@@ -259,6 +296,7 @@ impl Resolver<'_, '_> {
         let mut visitor = UnusedImportCheckVisitor {
             r: self,
             unused_imports: Default::default(),
+            extern_crate_items: Default::default(),
             base_use_tree: None,
             base_id: ast::DUMMY_NODE_ID,
             item_span: DUMMY_SP,
@@ -290,7 +328,7 @@ impl Resolver<'_, '_> {
             let ms = MultiSpan::from_spans(spans.clone());
             let mut span_snippets = spans
                 .iter()
-                .filter_map(|s| match visitor.r.tcx.sess.source_map().span_to_snippet(*s) {
+                .filter_map(|s| match tcx.sess.source_map().span_to_snippet(*s) {
                     Ok(s) => Some(format!("`{}`", s)),
                     _ => None,
                 })
@@ -317,7 +355,7 @@ impl Resolver<'_, '_> {
             // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
             // attribute; however, if not, suggest adding the attribute. There is no way to
             // retrieve attributes here because we do not have a `TyCtxt` yet.
-            let test_module_span = if visitor.r.tcx.sess.opts.test {
+            let test_module_span = if tcx.sess.opts.test {
                 None
             } else {
                 let parent_module = visitor.r.get_nearest_non_block_module(
@@ -346,5 +384,74 @@ impl Resolver<'_, '_> {
                 BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes, test_module_span),
             );
         }
+
+        for extern_crate in visitor.extern_crate_items {
+            let warn_if_unused = !extern_crate.ident.name.as_str().starts_with('_');
+
+            // If the crate is fully unused, we suggest removing it altogether.
+            // We do this in any edition.
+            if warn_if_unused {
+                if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
+                    visitor.r.lint_buffer.buffer_lint_with_diagnostic(
+                        UNUSED_EXTERN_CRATES,
+                        extern_crate.id,
+                        span,
+                        "unused extern crate",
+                        BuiltinLintDiagnostics::UnusedExternCrate {
+                            removal_span: extern_crate.span_with_attributes,
+                        },
+                    );
+                    continue;
+                }
+            }
+
+            // If we are not in Rust 2018 edition, then we don't make any further
+            // suggestions.
+            if !tcx.sess.rust_2018() {
+                continue;
+            }
+
+            // If the extern crate has any attributes, they may have funky
+            // semantics we can't faithfully represent using `use` (most
+            // notably `#[macro_use]`). Ignore it.
+            if extern_crate.has_attrs {
+                continue;
+            }
+
+            // If the extern crate is renamed, then we cannot suggest replacing it with a use as this
+            // would not insert the new name into the prelude, where other imports in the crate may be
+            // expecting it.
+            if extern_crate.renames {
+                continue;
+            }
+
+            // If the extern crate isn't in the extern prelude,
+            // there is no way it can be written as a `use`.
+            if !visitor
+                .r
+                .extern_prelude
+                .get(&extern_crate.ident)
+                .map_or(false, |entry| !entry.introduced_by_item)
+            {
+                continue;
+            }
+
+            let vis_span = extern_crate
+                .vis_span
+                .find_ancestor_inside(extern_crate.span)
+                .unwrap_or(extern_crate.vis_span);
+            let ident_span = extern_crate
+                .ident
+                .span
+                .find_ancestor_inside(extern_crate.span)
+                .unwrap_or(extern_crate.ident.span);
+            visitor.r.lint_buffer.buffer_lint_with_diagnostic(
+                UNUSED_EXTERN_CRATES,
+                extern_crate.id,
+                extern_crate.span,
+                "`extern crate` is not idiomatic in the new edition",
+                BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span },
+            );
+        }
     }
 }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index ee2d2301399..7add59ac627 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -189,7 +189,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         let container = match parent.kind {
-            ModuleKind::Def(kind, _, _) => self.tcx.def_kind_descr(kind, parent.def_id()),
+            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
+            // indirectly *calls* the resolver, and would cause a query cycle.
+            ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
             ModuleKind::Block => "block",
         };
 
@@ -1804,7 +1806,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         found("module")
                     } else {
                         match binding.res() {
-                            Res::Def(kind, id) => found(self.tcx.def_kind_descr(kind, id)),
+                            // Avoid using TyCtxt::def_kind_descr in the resolver, because it
+                            // indirectly *calls* the resolver, and would cause a query cycle.
+                            Res::Def(kind, id) => found(kind.descr(id)),
                             _ => found(ns_to_try.descr()),
                         }
                     }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7a1f14f71f2..1fdfb1a53d4 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -946,7 +946,6 @@ pub struct Resolver<'a, 'tcx> {
     has_pub_restricted: bool,
     used_imports: FxHashSet<NodeId>,
     maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
-    maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
 
     /// Privacy errors are delayed until the end in order to deduplicate them.
     privacy_errors: Vec<PrivacyError<'a>>,
@@ -1284,7 +1283,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             has_pub_restricted: false,
             used_imports: FxHashSet::default(),
             maybe_unused_trait_imports: Default::default(),
-            maybe_unused_extern_crates: Vec::new(),
 
             privacy_errors: Vec::new(),
             ambiguity_errors: Vec::new(),
@@ -1400,7 +1398,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let extern_crate_map = self.extern_crate_map;
         let reexport_map = self.reexport_map;
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
-        let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
         let glob_map = self.glob_map;
         let main_def = self.main_def;
         let confused_type_with_std_module = self.confused_type_with_std_module;
@@ -1414,12 +1411,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             reexport_map,
             glob_map,
             maybe_unused_trait_imports,
-            maybe_unused_extern_crates,
-            extern_prelude: self
-                .extern_prelude
-                .iter()
-                .map(|(ident, entry)| (ident.name, entry.introduced_by_item))
-                .collect(),
             main_def,
             trait_impls: self.trait_impls,
             proc_macros,
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index d3727a824b5..0c57ed1034a 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -124,6 +124,8 @@
 #![feature(const_inherent_unchecked_arith)]
 #![feature(const_int_unchecked_arith)]
 #![feature(const_intrinsic_forget)]
+#![feature(const_ipv4)]
+#![feature(const_ipv6)]
 #![feature(const_likely)]
 #![feature(const_maybe_uninit_uninit_array)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
@@ -179,6 +181,7 @@
 #![feature(const_slice_index)]
 #![feature(const_is_char_boundary)]
 #![feature(const_cstr_methods)]
+#![feature(ip)]
 #![feature(is_ascii_octdigit)]
 //
 // Language features:
@@ -349,6 +352,7 @@ pub mod cell;
 pub mod char;
 pub mod ffi;
 pub mod iter;
+pub mod net;
 pub mod option;
 pub mod panic;
 pub mod panicking;
diff --git a/library/std/src/net/display_buffer.rs b/library/core/src/net/display_buffer.rs
index 7aadf06e92f..7aadf06e92f 100644
--- a/library/std/src/net/display_buffer.rs
+++ b/library/core/src/net/display_buffer.rs
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
new file mode 100644
index 00000000000..954d88d548e
--- /dev/null
+++ b/library/core/src/net/ip_addr.rs
@@ -0,0 +1,2070 @@
+use crate::cmp::Ordering;
+use crate::fmt::{self, Write};
+use crate::mem::transmute;
+
+use super::display_buffer::DisplayBuffer;
+
+/// An IP address, either IPv4 or IPv6.
+///
+/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
+/// respective documentation for more details.
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+///
+/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
+/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+///
+/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));
+/// assert_eq!("::1".parse(), Ok(localhost_v6));
+///
+/// assert_eq!(localhost_v4.is_ipv6(), false);
+/// assert_eq!(localhost_v4.is_ipv4(), true);
+/// ```
+#[cfg_attr(not(test), rustc_diagnostic_item = "IpAddr")]
+#[stable(feature = "ip_addr", since = "1.7.0")]
+#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
+pub enum IpAddr {
+    /// An IPv4 address.
+    #[stable(feature = "ip_addr", since = "1.7.0")]
+    V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr),
+    /// An IPv6 address.
+    #[stable(feature = "ip_addr", since = "1.7.0")]
+    V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr),
+}
+
+/// An IPv4 address.
+///
+/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791].
+/// They are usually represented as four octets.
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
+///
+/// # Textual representation
+///
+/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
+/// notation, divided by `.` (this is called "dot-decimal notation").
+/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which
+/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943].
+///
+/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
+/// [`FromStr`]: crate::str::FromStr
+///
+/// # Examples
+///
+/// ```
+/// use std::net::Ipv4Addr;
+///
+/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
+/// assert_eq!("127.0.0.1".parse(), Ok(localhost));
+/// assert_eq!(localhost.is_loopback(), true);
+/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal
+/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
+/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Ipv4Addr {
+    octets: [u8; 4],
+}
+
+/// An IPv6 address.
+///
+/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
+/// They are usually represented as eight 16-bit segments.
+///
+/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+///
+/// # Embedding IPv4 Addresses
+///
+/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
+///
+/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined:
+/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated.
+///
+/// Both types of addresses are not assigned any special meaning by this implementation,
+/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`,
+/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is.
+/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address.
+///
+/// ### IPv4-Compatible IPv6 Addresses
+///
+/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated.
+/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows:
+///
+/// ```text
+/// |                80 bits               | 16 |      32 bits        |
+/// +--------------------------------------+--------------------------+
+/// |0000..............................0000|0000|    IPv4 address     |
+/// +--------------------------------------+----+---------------------+
+/// ```
+/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`.
+///
+/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`].
+/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address.
+///
+/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1
+///
+/// ### IPv4-Mapped IPv6 Addresses
+///
+/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2].
+/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows:
+///
+/// ```text
+/// |                80 bits               | 16 |      32 bits        |
+/// +--------------------------------------+--------------------------+
+/// |0000..............................0000|FFFF|    IPv4 address     |
+/// +--------------------------------------+----+---------------------+
+/// ```
+/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`.
+///
+/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`].
+/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address.
+/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use
+/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
+///
+/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
+///
+/// # Textual representation
+///
+/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
+/// an IPv6 address in text, but in general, each segments is written in hexadecimal
+/// notation, and segments are separated by `:`. For more information, see
+/// [IETF RFC 5952].
+///
+/// [`FromStr`]: crate::str::FromStr
+/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952
+///
+/// # Examples
+///
+/// ```
+/// use std::net::Ipv6Addr;
+///
+/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+/// assert_eq!("::1".parse(), Ok(localhost));
+/// assert_eq!(localhost.is_loopback(), true);
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Ipv6Addr {
+    octets: [u8; 16],
+}
+
+/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
+///
+/// # Stability Guarantees
+///
+/// Not all possible values for a multicast scope have been assigned.
+/// Future RFCs may introduce new scopes, which will be added as variants to this enum;
+/// because of this the enum is marked as `#[non_exhaustive]`.
+///
+/// # Examples
+/// ```
+/// #![feature(ip)]
+///
+/// use std::net::Ipv6Addr;
+/// use std::net::Ipv6MulticastScope::*;
+///
+/// // An IPv6 multicast address with global scope (`ff0e::`).
+/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0);
+///
+/// // Will print "Global scope".
+/// match address.multicast_scope() {
+///     Some(InterfaceLocal) => println!("Interface-Local scope"),
+///     Some(LinkLocal) => println!("Link-Local scope"),
+///     Some(RealmLocal) => println!("Realm-Local scope"),
+///     Some(AdminLocal) => println!("Admin-Local scope"),
+///     Some(SiteLocal) => println!("Site-Local scope"),
+///     Some(OrganizationLocal) => println!("Organization-Local scope"),
+///     Some(Global) => println!("Global scope"),
+///     Some(_) => println!("Unknown scope"),
+///     None => println!("Not a multicast address!")
+/// }
+///
+/// ```
+///
+/// [IPv6 multicast address]: Ipv6Addr
+/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[unstable(feature = "ip", issue = "27709")]
+#[non_exhaustive]
+pub enum Ipv6MulticastScope {
+    /// Interface-Local scope.
+    InterfaceLocal,
+    /// Link-Local scope.
+    LinkLocal,
+    /// Realm-Local scope.
+    RealmLocal,
+    /// Admin-Local scope.
+    AdminLocal,
+    /// Site-Local scope.
+    SiteLocal,
+    /// Organization-Local scope.
+    OrganizationLocal,
+    /// Global scope.
+    Global,
+}
+
+impl IpAddr {
+    /// Returns [`true`] for the special 'unspecified' address.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_unspecified()`] and
+    /// [`Ipv6Addr::is_unspecified()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unspecified(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_unspecified(),
+            IpAddr::V6(ip) => ip.is_unspecified(),
+        }
+    }
+
+    /// Returns [`true`] if this is a loopback address.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_loopback()`] and
+    /// [`Ipv6Addr::is_loopback()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_loopback(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_loopback(),
+            IpAddr::V6(ip) => ip.is_loopback(),
+        }
+    }
+
+    /// Returns [`true`] if the address appears to be globally routable.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_global()`] and
+    /// [`Ipv6Addr::is_global()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_global(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_global(),
+            IpAddr::V6(ip) => ip.is_global(),
+        }
+    }
+
+    /// Returns [`true`] if this is a multicast address.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_multicast()`] and
+    /// [`Ipv6Addr::is_multicast()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_multicast(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_multicast(),
+            IpAddr::V6(ip) => ip.is_multicast(),
+        }
+    }
+
+    /// Returns [`true`] if this address is in a range designated for documentation.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_documentation()`] and
+    /// [`Ipv6Addr::is_documentation()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true);
+    /// assert_eq!(
+    ///     IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(),
+    ///     true
+    /// );
+    /// ```
+    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_documentation(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_documentation(),
+            IpAddr::V6(ip) => ip.is_documentation(),
+        }
+    }
+
+    /// Returns [`true`] if this address is in a range designated for benchmarking.
+    ///
+    /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and
+    /// [`Ipv6Addr::is_benchmarking()`] for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
+    /// ```
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_benchmarking(&self) -> bool {
+        match self {
+            IpAddr::V4(ip) => ip.is_benchmarking(),
+            IpAddr::V6(ip) => ip.is_benchmarking(),
+        }
+    }
+
+    /// Returns [`true`] if this address is an [`IPv4` address], and [`false`]
+    /// otherwise.
+    ///
+    /// [`IPv4` address]: IpAddr::V4
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_ipv4(&self) -> bool {
+        matches!(self, IpAddr::V4(_))
+    }
+
+    /// Returns [`true`] if this address is an [`IPv6` address], and [`false`]
+    /// otherwise.
+    ///
+    /// [`IPv6` address]: IpAddr::V6
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_ipv6(&self) -> bool {
+        matches!(self, IpAddr::V6(_))
+    }
+
+    /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it
+    /// return `self` as-is.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false);
+    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true);
+    /// ```
+    #[inline]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    pub const fn to_canonical(&self) -> IpAddr {
+        match self {
+            &v4 @ IpAddr::V4(_) => v4,
+            IpAddr::V6(v6) => v6.to_canonical(),
+        }
+    }
+}
+
+impl Ipv4Addr {
+    /// Creates a new IPv4 address from four eight-bit octets.
+    ///
+    /// The result will represent the IP address `a`.`b`.`c`.`d`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[inline]
+    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+        Ipv4Addr { octets: [a, b, c, d] }
+    }
+
+    /// An IPv4 address with the address pointing to localhost: `127.0.0.1`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::LOCALHOST;
+    /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
+    /// ```
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
+
+    /// An IPv4 address representing an unspecified address: `0.0.0.0`
+    ///
+    /// This corresponds to the constant `INADDR_ANY` in other languages.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::UNSPECIFIED;
+    /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
+    /// ```
+    #[doc(alias = "INADDR_ANY")]
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
+
+    /// An IPv4 address representing the broadcast address: `255.255.255.255`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::BROADCAST;
+    /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255));
+    /// ```
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
+
+    /// Returns the four eight-bit integers that make up this address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+    /// assert_eq!(addr.octets(), [127, 0, 0, 1]);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[inline]
+    pub const fn octets(&self) -> [u8; 4] {
+        self.octets
+    }
+
+    /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
+    ///
+    /// This property is defined in _UNIX Network Programming, Second Edition_,
+    /// W. Richard Stevens, p. 891; see also [ip7].
+    ///
+    /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
+    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
+    #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unspecified(&self) -> bool {
+        u32::from_be_bytes(self.octets) == 0
+    }
+
+    /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`).
+    ///
+    /// This property is defined by [IETF RFC 1122].
+    ///
+    /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
+    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_loopback(&self) -> bool {
+        self.octets()[0] == 127
+    }
+
+    /// Returns [`true`] if this is a private address.
+    ///
+    /// The private address ranges are defined in [IETF RFC 1918] and include:
+    ///
+    ///  - `10.0.0.0/8`
+    ///  - `172.16.0.0/12`
+    ///  - `192.168.0.0/16`
+    ///
+    /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
+    /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
+    /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_private(&self) -> bool {
+        match self.octets() {
+            [10, ..] => true,
+            [172, b, ..] if b >= 16 && b <= 31 => true,
+            [192, 168, ..] => true,
+            _ => false,
+        }
+    }
+
+    /// Returns [`true`] if the address is link-local (`169.254.0.0/16`).
+    ///
+    /// This property is defined by [IETF RFC 3927].
+    ///
+    /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
+    /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
+    /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_link_local(&self) -> bool {
+        matches!(self.octets(), [169, 254, ..])
+    }
+
+    /// Returns [`true`] if the address appears to be globally reachable
+    /// as specified by the [IANA IPv4 Special-Purpose Address Registry].
+    /// Whether or not an address is practically reachable will depend on your network configuration.
+    ///
+    /// Most IPv4 addresses are globally reachable;
+    /// unless they are specifically defined as *not* globally reachable.
+    ///
+    /// Non-exhaustive list of notable addresses that are not globally reachable:
+    ///
+    /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified))
+    /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private))
+    /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared))
+    /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback))
+    /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local))
+    /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation))
+    /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking))
+    /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved))
+    /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast))
+    ///
+    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry].
+    ///
+    /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
+    /// [unspecified address]: Ipv4Addr::UNSPECIFIED
+    /// [broadcast address]: Ipv4Addr::BROADCAST
+
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv4Addr;
+    ///
+    /// // Most IPv4 addresses are globally reachable:
+    /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
+    ///
+    /// // However some addresses have been assigned a special meaning
+    /// // that makes them not globally reachable. Some examples are:
+    ///
+    /// // The unspecified address (`0.0.0.0`)
+    /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false);
+    ///
+    /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16)
+    /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
+    /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
+    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
+    ///
+    /// // Addresses in the shared address space (`100.64.0.0/10`)
+    /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
+    ///
+    /// // The loopback addresses (`127.0.0.0/8`)
+    /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false);
+    ///
+    /// // Link-local addresses (`169.254.0.0/16`)
+    /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
+    ///
+    /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`)
+    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
+    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
+    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
+    ///
+    /// // Addresses reserved for benchmarking (`198.18.0.0/15`)
+    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
+    ///
+    /// // Reserved addresses (`240.0.0.0/4`)
+    /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
+    ///
+    /// // The broadcast address (`255.255.255.255`)
+    /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
+    ///
+    /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry.
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_global(&self) -> bool {
+        !(self.octets()[0] == 0 // "This network"
+            || self.is_private()
+            || self.is_shared()
+            || self.is_loopback()
+            || self.is_link_local()
+            // addresses reserved for future protocols (`192.0.0.0/24`)
+            ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
+            || self.is_documentation()
+            || self.is_benchmarking()
+            || self.is_reserved()
+            || self.is_broadcast())
+    }
+
+    /// Returns [`true`] if this address is part of the Shared Address Space defined in
+    /// [IETF RFC 6598] (`100.64.0.0/10`).
+    ///
+    /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true);
+    /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true);
+    /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_shared(&self) -> bool {
+        self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
+    }
+
+    /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
+    /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
+    /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
+    ///
+    /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544
+    /// [errata 423]: https://www.rfc-editor.org/errata/eid423
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false);
+    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true);
+    /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true);
+    /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_benchmarking(&self) -> bool {
+        self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
+    }
+
+    /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112]
+    /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the
+    /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since
+    /// it is obviously not reserved for future use.
+    ///
+    /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
+    ///
+    /// # Warning
+    ///
+    /// As IANA assigns new addresses, this method will be
+    /// updated. This may result in non-reserved addresses being
+    /// treated as reserved in code that relies on an outdated version
+    /// of this method.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true);
+    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true);
+    ///
+    /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false);
+    /// // The broadcast address is not considered as reserved for future use by this implementation
+    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_reserved(&self) -> bool {
+        self.octets()[0] & 240 == 240 && !self.is_broadcast()
+    }
+
+    /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`).
+    ///
+    /// Multicast addresses have a most significant octet between `224` and `239`,
+    /// and is defined by [IETF RFC 5771].
+    ///
+    /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
+    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
+    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_multicast(&self) -> bool {
+        self.octets()[0] >= 224 && self.octets()[0] <= 239
+    }
+
+    /// Returns [`true`] if this is a broadcast address (`255.255.255.255`).
+    ///
+    /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919].
+    ///
+    /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
+    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_broadcast(&self) -> bool {
+        u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
+    }
+
+    /// Returns [`true`] if this address is in a range designated for documentation.
+    ///
+    /// This is defined in [IETF RFC 5737]:
+    ///
+    /// - `192.0.2.0/24` (TEST-NET-1)
+    /// - `198.51.100.0/24` (TEST-NET-2)
+    /// - `203.0.113.0/24` (TEST-NET-3)
+    ///
+    /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
+    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
+    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
+    /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_documentation(&self) -> bool {
+        matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
+    }
+
+    /// Converts this address to an [IPv4-compatible] [`IPv6` address].
+    ///
+    /// `a.b.c.d` becomes `::a.b.c.d`
+    ///
+    /// Note that IPv4-compatible addresses have been officially deprecated.
+    /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead.
+    ///
+    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
+    /// [`IPv6` address]: Ipv6Addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(
+    ///     Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
+    ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff)
+    /// );
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] }
+    }
+
+    /// Converts this address to an [IPv4-mapped] [`IPv6` address].
+    ///
+    /// `a.b.c.d` becomes `::ffff:a.b.c.d`
+    ///
+    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
+    /// [`IPv6` address]: Ipv6Addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
+    ///            Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff));
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
+        let [a, b, c, d] = self.octets();
+        Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }
+    }
+}
+
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl fmt::Display for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            IpAddr::V4(ip) => ip.fmt(fmt),
+            IpAddr::V6(ip) => ip.fmt(fmt),
+        }
+    }
+}
+
+#[stable(feature = "ip_addr", since = "1.7.0")]
+impl fmt::Debug for IpAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<Ipv4Addr> for IpAddr {
+    /// Copies this address to a new `IpAddr::V4`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr};
+    ///
+    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
+    ///
+    /// assert_eq!(
+    ///     IpAddr::V4(addr),
+    ///     IpAddr::from(addr)
+    /// )
+    /// ```
+    #[inline]
+    fn from(ipv4: Ipv4Addr) -> IpAddr {
+        IpAddr::V4(ipv4)
+    }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<Ipv6Addr> for IpAddr {
+    /// Copies this address to a new `IpAddr::V6`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv6Addr};
+    ///
+    /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
+    ///
+    /// assert_eq!(
+    ///     IpAddr::V6(addr),
+    ///     IpAddr::from(addr)
+    /// );
+    /// ```
+    #[inline]
+    fn from(ipv6: Ipv6Addr) -> IpAddr {
+        IpAddr::V6(ipv6)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let octets = self.octets();
+
+        // If there are no alignment requirements, write the IP address directly to `f`.
+        // Otherwise, write it to a local buffer and then use `f.pad`.
+        if fmt.precision().is_none() && fmt.width().is_none() {
+            write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+        } else {
+            const LONGEST_IPV4_ADDR: &str = "255.255.255.255";
+
+            let mut buf = DisplayBuffer::<{ LONGEST_IPV4_ADDR.len() }>::new();
+            // Buffer is long enough for the longest possible IPv4 address, so this should never fail.
+            write!(buf, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
+
+            fmt.pad(buf.as_str())
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<Ipv4Addr> for IpAddr {
+    #[inline]
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        match self {
+            IpAddr::V4(v4) => v4 == other,
+            IpAddr::V6(_) => false,
+        }
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<IpAddr> for Ipv4Addr {
+    #[inline]
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other {
+            IpAddr::V4(v4) => self == v4,
+            IpAddr::V6(_) => false,
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Ipv4Addr {
+    #[inline]
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<Ipv4Addr> for IpAddr {
+    #[inline]
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(v4) => v4.partial_cmp(other),
+            IpAddr::V6(_) => Some(Ordering::Greater),
+        }
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<IpAddr> for Ipv4Addr {
+    #[inline]
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(v4) => self.partial_cmp(v4),
+            IpAddr::V6(_) => Some(Ordering::Less),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Ipv4Addr {
+    #[inline]
+    fn cmp(&self, other: &Ipv4Addr) -> Ordering {
+        self.octets.cmp(&other.octets)
+    }
+}
+
+#[stable(feature = "ip_u32", since = "1.1.0")]
+impl From<Ipv4Addr> for u32 {
+    /// Converts an `Ipv4Addr` into a host byte order `u32`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78);
+    /// assert_eq!(0x12345678, u32::from(addr));
+    /// ```
+    #[inline]
+    fn from(ip: Ipv4Addr) -> u32 {
+        u32::from_be_bytes(ip.octets)
+    }
+}
+
+#[stable(feature = "ip_u32", since = "1.1.0")]
+impl From<u32> for Ipv4Addr {
+    /// Converts a host byte order `u32` into an `Ipv4Addr`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from(0x12345678);
+    /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
+    /// ```
+    #[inline]
+    fn from(ip: u32) -> Ipv4Addr {
+        Ipv4Addr { octets: ip.to_be_bytes() }
+    }
+}
+
+#[stable(feature = "from_slice_v4", since = "1.9.0")]
+impl From<[u8; 4]> for Ipv4Addr {
+    /// Creates an `Ipv4Addr` from a four element byte array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv4Addr;
+    ///
+    /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]);
+    /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
+    /// ```
+    #[inline]
+    fn from(octets: [u8; 4]) -> Ipv4Addr {
+        Ipv4Addr { octets }
+    }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u8; 4]> for IpAddr {
+    /// Creates an `IpAddr::V4` from a four element byte array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr};
+    ///
+    /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]);
+    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr);
+    /// ```
+    #[inline]
+    fn from(octets: [u8; 4]) -> IpAddr {
+        IpAddr::V4(Ipv4Addr::from(octets))
+    }
+}
+
+impl Ipv6Addr {
+    /// Creates a new IPv6 address from eight 16-bit segments.
+    ///
+    /// The result will represent the IP address `a:b:c:d:e:f:g:h`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[inline]
+    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
+        let addr16 = [
+            a.to_be(),
+            b.to_be(),
+            c.to_be(),
+            d.to_be(),
+            e.to_be(),
+            f.to_be(),
+            g.to_be(),
+            h.to_be(),
+        ];
+        Ipv6Addr {
+            // All elements in `addr16` are big endian.
+            // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
+            octets: unsafe { transmute::<_, [u8; 16]>(addr16) },
+        }
+    }
+
+    /// An IPv6 address representing localhost: `::1`.
+    ///
+    /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
+    /// languages.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::LOCALHOST;
+    /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    /// ```
+    #[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
+    #[doc(alias = "in6addr_loopback")]
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+
+    /// An IPv6 address representing the unspecified address: `::`
+    ///
+    /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::UNSPECIFIED;
+    /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+    /// ```
+    #[doc(alias = "IN6ADDR_ANY_INIT")]
+    #[doc(alias = "in6addr_any")]
+    #[stable(feature = "ip_constructors", since = "1.30.0")]
+    pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+
+    /// Returns the eight 16-bit segments that make up this address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
+    ///            [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[inline]
+    pub const fn segments(&self) -> [u16; 8] {
+        // All elements in `self.octets` must be big endian.
+        // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
+        let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) };
+        // We want native endian u16
+        [
+            u16::from_be(a),
+            u16::from_be(b),
+            u16::from_be(c),
+            u16::from_be(d),
+            u16::from_be(e),
+            u16::from_be(f),
+            u16::from_be(g),
+            u16::from_be(h),
+        ]
+    }
+
+    /// Returns [`true`] for the special 'unspecified' address (`::`).
+    ///
+    /// This property is defined in [IETF RFC 4291].
+    ///
+    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unspecified(&self) -> bool {
+        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
+    }
+
+    /// Returns [`true`] if this is the [loopback address] (`::1`),
+    /// as defined in [IETF RFC 4291 section 2.5.3].
+    ///
+    /// Contrary to IPv4, in IPv6 there is only one loopback address.
+    ///
+    /// [loopback address]: Ipv6Addr::LOCALHOST
+    /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_loopback(&self) -> bool {
+        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
+    }
+
+    /// Returns [`true`] if the address appears to be globally reachable
+    /// as specified by the [IANA IPv6 Special-Purpose Address Registry].
+    /// Whether or not an address is practically reachable will depend on your network configuration.
+    ///
+    /// Most IPv6 addresses are globally reachable;
+    /// unless they are specifically defined as *not* globally reachable.
+    ///
+    /// Non-exhaustive list of notable addresses that are not globally reachable:
+    /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
+    /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
+    /// - IPv4-mapped addresses
+    /// - Addresses reserved for benchmarking
+    /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
+    /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
+    /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
+    ///
+    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
+    ///
+    /// Note that an address having global scope is not the same as being globally reachable,
+    /// and there is no direct relation between the two concepts: There exist addresses with global scope
+    /// that are not globally reachable (for example unique local addresses),
+    /// and addresses that are globally reachable without having global scope
+    /// (multicast addresses with non-global scope).
+    ///
+    /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
+    /// [unspecified address]: Ipv6Addr::UNSPECIFIED
+    /// [loopback address]: Ipv6Addr::LOCALHOST
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// // Most IPv6 addresses are globally reachable:
+    /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
+    ///
+    /// // However some addresses have been assigned a special meaning
+    /// // that makes them not globally reachable. Some examples are:
+    ///
+    /// // The unspecified address (`::`)
+    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
+    ///
+    /// // The loopback address (`::1`)
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
+    ///
+    /// // IPv4-mapped addresses (`::ffff:0:0/96`)
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
+    ///
+    /// // Addresses reserved for benchmarking (`2001:2::/48`)
+    /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
+    ///
+    /// // Addresses reserved for documentation (`2001:db8::/32`)
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // Unique local addresses (`fc00::/7`)
+    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // Unicast addresses with link-local scope (`fe80::/10`)
+    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
+    ///
+    /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_global(&self) -> bool {
+        !(self.is_unspecified()
+            || self.is_loopback()
+            // IPv4-mapped Address (`::ffff:0:0/96`)
+            || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
+            // IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
+            || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
+            // Discard-Only Address Block (`100::/64`)
+            || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
+            // IETF Protocol Assignments (`2001::/23`)
+            || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
+                && !(
+                    // Port Control Protocol Anycast (`2001:1::1`)
+                    u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
+                    // Traversal Using Relays around NAT Anycast (`2001:1::2`)
+                    || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
+                    // AMT (`2001:3::/32`)
+                    || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
+                    // AS112-v6 (`2001:4:112::/48`)
+                    || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
+                    // ORCHIDv2 (`2001:20::/28`)
+                    || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
+                ))
+            || self.is_documentation()
+            || self.is_unique_local()
+            || self.is_unicast_link_local())
+    }
+
+    /// Returns [`true`] if this is a unique local address (`fc00::/7`).
+    ///
+    /// This property is defined in [IETF RFC 4193].
+    ///
+    /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false);
+    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unique_local(&self) -> bool {
+        (self.segments()[0] & 0xfe00) == 0xfc00
+    }
+
+    /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291].
+    /// Any address that is not a [multicast address] (`ff00::/8`) is unicast.
+    ///
+    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+    /// [multicast address]: Ipv6Addr::is_multicast
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// // The unspecified and loopback addresses are unicast.
+    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true);
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true);
+    ///
+    /// // Any address that is not a multicast address (`ff00::/8`) is unicast.
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true);
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unicast(&self) -> bool {
+        !self.is_multicast()
+    }
+
+    /// Returns `true` if the address is a unicast address with link-local scope,
+    /// as defined in [RFC 4291].
+    ///
+    /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
+    /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
+    /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
+    ///
+    /// ```text
+    /// | 10 bits  |         54 bits         |          64 bits           |
+    /// +----------+-------------------------+----------------------------+
+    /// |1111111010|           0             |       interface ID         |
+    /// +----------+-------------------------+----------------------------+
+    /// ```
+    /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
+    /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
+    /// and those addresses will have link-local scope.
+    ///
+    /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
+    /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
+    ///
+    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
+    /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
+    /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
+    /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
+    /// [loopback address]: Ipv6Addr::LOCALHOST
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// // The loopback address (`::1`) does not actually have link-local scope.
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
+    ///
+    /// // Only addresses in `fe80::/10` have link-local scope.
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
+    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
+    ///
+    /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
+    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
+    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unicast_link_local(&self) -> bool {
+        (self.segments()[0] & 0xffc0) == 0xfe80
+    }
+
+    /// Returns [`true`] if this is an address reserved for documentation
+    /// (`2001:db8::/32`).
+    ///
+    /// This property is defined in [IETF RFC 3849].
+    ///
+    /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_documentation(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
+    }
+
+    /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`).
+    ///
+    /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`.
+    /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`.
+    ///
+    /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180
+    /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false);
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true);
+    /// ```
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_benchmarking(&self) -> bool {
+        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0)
+    }
+
+    /// Returns [`true`] if the address is a globally routable unicast address.
+    ///
+    /// The following return false:
+    ///
+    /// - the loopback address
+    /// - the link-local addresses
+    /// - unique local addresses
+    /// - the unspecified address
+    /// - the address range reserved for documentation
+    ///
+    /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7]
+    ///
+    /// ```no_rust
+    /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer
+    /// be supported in new implementations (i.e., new implementations must treat this prefix as
+    /// Global Unicast).
+    /// ```
+    ///
+    /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn is_unicast_global(&self) -> bool {
+        self.is_unicast()
+            && !self.is_loopback()
+            && !self.is_unicast_link_local()
+            && !self.is_unique_local()
+            && !self.is_unspecified()
+            && !self.is_documentation()
+            && !self.is_benchmarking()
+    }
+
+    /// Returns the address's multicast scope if the address is multicast.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    ///
+    /// use std::net::{Ipv6Addr, Ipv6MulticastScope};
+    ///
+    /// assert_eq!(
+    ///     Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(),
+    ///     Some(Ipv6MulticastScope::Global)
+    /// );
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use]
+    #[inline]
+    pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
+        if self.is_multicast() {
+            match self.segments()[0] & 0x000f {
+                1 => Some(Ipv6MulticastScope::InterfaceLocal),
+                2 => Some(Ipv6MulticastScope::LinkLocal),
+                3 => Some(Ipv6MulticastScope::RealmLocal),
+                4 => Some(Ipv6MulticastScope::AdminLocal),
+                5 => Some(Ipv6MulticastScope::SiteLocal),
+                8 => Some(Ipv6MulticastScope::OrganizationLocal),
+                14 => Some(Ipv6MulticastScope::Global),
+                _ => None,
+            }
+        } else {
+            None
+        }
+    }
+
+    /// Returns [`true`] if this is a multicast address (`ff00::/8`).
+    ///
+    /// This property is defined by [IETF RFC 4291].
+    ///
+    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(since = "1.7.0", feature = "ip_17")]
+    #[must_use]
+    #[inline]
+    pub const fn is_multicast(&self) -> bool {
+        (self.segments()[0] & 0xff00) == 0xff00
+    }
+
+    /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address,
+    /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
+    ///
+    /// `::ffff:a.b.c.d` becomes `a.b.c.d`.
+    /// All addresses *not* starting with `::ffff` will return `None`.
+    ///
+    /// [`IPv4` address]: Ipv4Addr
+    /// [IPv4-mapped]: Ipv6Addr
+    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(),
+    ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
+        match self.octets() {
+            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
+                Some(Ipv4Addr::new(a, b, c, d))
+            }
+            _ => None,
+        }
+    }
+
+    /// Converts this address to an [`IPv4` address] if it is either
+    /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1],
+    /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2],
+    /// otherwise returns [`None`].
+    ///
+    /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use
+    /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
+    ///
+    /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`.
+    /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`.
+    ///
+    /// [`IPv4` address]: Ipv4Addr
+    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
+    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
+    /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1
+    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
+    ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
+    ///            Some(Ipv4Addr::new(0, 0, 0, 1)));
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
+        if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
+            let [a, b] = ab.to_be_bytes();
+            let [c, d] = cd.to_be_bytes();
+            Some(Ipv4Addr::new(a, b, c, d))
+        } else {
+            None
+        }
+    }
+
+    /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it
+    /// returns self wrapped in an `IpAddr::V6`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ip)]
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false);
+    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true);
+    /// ```
+    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
+    #[must_use = "this returns the result of the operation, \
+                  without modifying the original"]
+    #[inline]
+    pub const fn to_canonical(&self) -> IpAddr {
+        if let Some(mapped) = self.to_ipv4_mapped() {
+            return IpAddr::V4(mapped);
+        }
+        IpAddr::V6(*self)
+    }
+
+    /// Returns the sixteen eight-bit integers the IPv6 address consists of.
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
+    ///            [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+    /// ```
+    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
+    #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+    #[must_use]
+    #[inline]
+    pub const fn octets(&self) -> [u8; 16] {
+        self.octets
+    }
+}
+
+/// Write an Ipv6Addr, conforming to the canonical style described by
+/// [RFC 5952](https://tools.ietf.org/html/rfc5952).
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Ipv6Addr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // If there are no alignment requirements, write the IP address directly to `f`.
+        // Otherwise, write it to a local buffer and then use `f.pad`.
+        if f.precision().is_none() && f.width().is_none() {
+            let segments = self.segments();
+
+            // Special case for :: and ::1; otherwise they get written with the
+            // IPv4 formatter
+            if self.is_unspecified() {
+                f.write_str("::")
+            } else if self.is_loopback() {
+                f.write_str("::1")
+            } else if let Some(ipv4) = self.to_ipv4() {
+                match segments[5] {
+                    // IPv4 Compatible address
+                    0 => write!(f, "::{}", ipv4),
+                    // IPv4 Mapped address
+                    0xffff => write!(f, "::ffff:{}", ipv4),
+                    _ => unreachable!(),
+                }
+            } else {
+                #[derive(Copy, Clone, Default)]
+                struct Span {
+                    start: usize,
+                    len: usize,
+                }
+
+                // Find the inner 0 span
+                let zeroes = {
+                    let mut longest = Span::default();
+                    let mut current = Span::default();
+
+                    for (i, &segment) in segments.iter().enumerate() {
+                        if segment == 0 {
+                            if current.len == 0 {
+                                current.start = i;
+                            }
+
+                            current.len += 1;
+
+                            if current.len > longest.len {
+                                longest = current;
+                            }
+                        } else {
+                            current = Span::default();
+                        }
+                    }
+
+                    longest
+                };
+
+                /// Write a colon-separated part of the address
+                #[inline]
+                fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
+                    if let Some((first, tail)) = chunk.split_first() {
+                        write!(f, "{:x}", first)?;
+                        for segment in tail {
+                            f.write_char(':')?;
+                            write!(f, "{:x}", segment)?;
+                        }
+                    }
+                    Ok(())
+                }
+
+                if zeroes.len > 1 {
+                    fmt_subslice(f, &segments[..zeroes.start])?;
+                    f.write_str("::")?;
+                    fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
+                } else {
+                    fmt_subslice(f, &segments)
+                }
+            }
+        } else {
+            const LONGEST_IPV6_ADDR: &str = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
+
+            let mut buf = DisplayBuffer::<{ LONGEST_IPV6_ADDR.len() }>::new();
+            // Buffer is long enough for the longest possible IPv6 address, so this should never fail.
+            write!(buf, "{}", self).unwrap();
+
+            f.pad(buf.as_str())
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Ipv6Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<IpAddr> for Ipv6Addr {
+    #[inline]
+    fn eq(&self, other: &IpAddr) -> bool {
+        match other {
+            IpAddr::V4(_) => false,
+            IpAddr::V6(v6) => self == v6,
+        }
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialEq<Ipv6Addr> for IpAddr {
+    #[inline]
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        match self {
+            IpAddr::V4(_) => false,
+            IpAddr::V6(v6) => v6 == other,
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Ipv6Addr {
+    #[inline]
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<Ipv6Addr> for IpAddr {
+    #[inline]
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        match self {
+            IpAddr::V4(_) => Some(Ordering::Less),
+            IpAddr::V6(v6) => v6.partial_cmp(other),
+        }
+    }
+}
+
+#[stable(feature = "ip_cmp", since = "1.16.0")]
+impl PartialOrd<IpAddr> for Ipv6Addr {
+    #[inline]
+    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
+        match other {
+            IpAddr::V4(_) => Some(Ordering::Greater),
+            IpAddr::V6(v6) => self.partial_cmp(v6),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Ipv6Addr {
+    #[inline]
+    fn cmp(&self, other: &Ipv6Addr) -> Ordering {
+        self.segments().cmp(&other.segments())
+    }
+}
+
+#[stable(feature = "i128", since = "1.26.0")]
+impl From<Ipv6Addr> for u128 {
+    /// Convert an `Ipv6Addr` into a host byte order `u128`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::new(
+    ///     0x1020, 0x3040, 0x5060, 0x7080,
+    ///     0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
+    /// );
+    /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
+    /// ```
+    #[inline]
+    fn from(ip: Ipv6Addr) -> u128 {
+        u128::from_be_bytes(ip.octets)
+    }
+}
+#[stable(feature = "i128", since = "1.26.0")]
+impl From<u128> for Ipv6Addr {
+    /// Convert a host byte order `u128` into an `Ipv6Addr`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
+    /// assert_eq!(
+    ///     Ipv6Addr::new(
+    ///         0x1020, 0x3040, 0x5060, 0x7080,
+    ///         0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
+    ///     ),
+    ///     addr);
+    /// ```
+    #[inline]
+    fn from(ip: u128) -> Ipv6Addr {
+        Ipv6Addr::from(ip.to_be_bytes())
+    }
+}
+
+#[stable(feature = "ipv6_from_octets", since = "1.9.0")]
+impl From<[u8; 16]> for Ipv6Addr {
+    /// Creates an `Ipv6Addr` from a sixteen element byte array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from([
+    ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
+    ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
+    /// ]);
+    /// assert_eq!(
+    ///     Ipv6Addr::new(
+    ///         0x1918, 0x1716,
+    ///         0x1514, 0x1312,
+    ///         0x1110, 0x0f0e,
+    ///         0x0d0c, 0x0b0a
+    ///     ),
+    ///     addr
+    /// );
+    /// ```
+    #[inline]
+    fn from(octets: [u8; 16]) -> Ipv6Addr {
+        Ipv6Addr { octets }
+    }
+}
+
+#[stable(feature = "ipv6_from_segments", since = "1.16.0")]
+impl From<[u16; 8]> for Ipv6Addr {
+    /// Creates an `Ipv6Addr` from an eight element 16-bit array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::Ipv6Addr;
+    ///
+    /// let addr = Ipv6Addr::from([
+    ///     525u16, 524u16, 523u16, 522u16,
+    ///     521u16, 520u16, 519u16, 518u16,
+    /// ]);
+    /// assert_eq!(
+    ///     Ipv6Addr::new(
+    ///         0x20d, 0x20c,
+    ///         0x20b, 0x20a,
+    ///         0x209, 0x208,
+    ///         0x207, 0x206
+    ///     ),
+    ///     addr
+    /// );
+    /// ```
+    #[inline]
+    fn from(segments: [u16; 8]) -> Ipv6Addr {
+        let [a, b, c, d, e, f, g, h] = segments;
+        Ipv6Addr::new(a, b, c, d, e, f, g, h)
+    }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u8; 16]> for IpAddr {
+    /// Creates an `IpAddr::V6` from a sixteen element byte array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv6Addr};
+    ///
+    /// let addr = IpAddr::from([
+    ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
+    ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
+    /// ]);
+    /// assert_eq!(
+    ///     IpAddr::V6(Ipv6Addr::new(
+    ///         0x1918, 0x1716,
+    ///         0x1514, 0x1312,
+    ///         0x1110, 0x0f0e,
+    ///         0x0d0c, 0x0b0a
+    ///     )),
+    ///     addr
+    /// );
+    /// ```
+    #[inline]
+    fn from(octets: [u8; 16]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(octets))
+    }
+}
+
+#[stable(feature = "ip_from_slice", since = "1.17.0")]
+impl From<[u16; 8]> for IpAddr {
+    /// Creates an `IpAddr::V6` from an eight element 16-bit array.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv6Addr};
+    ///
+    /// let addr = IpAddr::from([
+    ///     525u16, 524u16, 523u16, 522u16,
+    ///     521u16, 520u16, 519u16, 518u16,
+    /// ]);
+    /// assert_eq!(
+    ///     IpAddr::V6(Ipv6Addr::new(
+    ///         0x20d, 0x20c,
+    ///         0x20b, 0x20a,
+    ///         0x209, 0x208,
+    ///         0x207, 0x206
+    ///     )),
+    ///     addr
+    /// );
+    /// ```
+    #[inline]
+    fn from(segments: [u16; 8]) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::from(segments))
+    }
+}
diff --git a/library/core/src/net/mod.rs b/library/core/src/net/mod.rs
new file mode 100644
index 00000000000..31f5f5d3c22
--- /dev/null
+++ b/library/core/src/net/mod.rs
@@ -0,0 +1,24 @@
+//! Networking primitives for IP communication.
+//!
+//! This module provides types for IP and socket addresses.
+//!
+//! # Organization
+//!
+//! * [`IpAddr`] represents IP addresses of either IPv4 or IPv6; [`Ipv4Addr`] and
+//!   [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses
+//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`]
+//!   and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses
+
+#![unstable(feature = "ip_in_core", issue = "108443")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::parser::AddrParseError;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6};
+
+mod display_buffer;
+mod ip_addr;
+mod parser;
+mod socket_addr;
diff --git a/library/std/src/net/parser.rs b/library/core/src/net/parser.rs
index a38031c48c8..a08d2792d04 100644
--- a/library/std/src/net/parser.rs
+++ b/library/core/src/net/parser.rs
@@ -3,9 +3,7 @@
 //! This module is "publicly exported" through the `FromStr` implementations
 //! below.
 
-#[cfg(test)]
-mod tests;
-
+use crate::convert::TryInto;
 use crate::error::Error;
 use crate::fmt;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
new file mode 100644
index 00000000000..0d25ab1d5e1
--- /dev/null
+++ b/library/core/src/net/socket_addr.rs
@@ -0,0 +1,664 @@
+use crate::cmp::Ordering;
+use crate::fmt::{self, Write};
+use crate::hash;
+use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+
+use super::display_buffer::DisplayBuffer;
+
+/// An internet socket address, either IPv4 or IPv6.
+///
+/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well
+/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and
+/// [`SocketAddrV6`]'s respective documentation for more details.
+///
+/// The size of a `SocketAddr` instance may vary depending on the target operating
+/// system.
+///
+/// [IP address]: IpAddr
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+///
+/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+///
+/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
+/// assert_eq!(socket.port(), 8080);
+/// assert_eq!(socket.is_ipv4(), true);
+/// ```
+#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum SocketAddr {
+    /// An IPv4 socket address.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
+    /// An IPv6 socket address.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
+}
+
+/// An IPv4 socket address.
+///
+/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as
+/// stated in [IETF RFC 793].
+///
+/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
+///
+/// The size of a `SocketAddrV4` struct may vary depending on the target operating
+/// system. Do not assume that this type has the same memory layout as the underlying
+/// system representation.
+///
+/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
+/// [`IPv4` address]: Ipv4Addr
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{Ipv4Addr, SocketAddrV4};
+///
+/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+///
+/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
+/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+/// assert_eq!(socket.port(), 8080);
+/// ```
+#[derive(Copy, Clone, Eq, PartialEq)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV4 {
+    ip: Ipv4Addr,
+    port: u16,
+}
+
+/// An IPv6 socket address.
+///
+/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well
+/// as fields containing the traffic class, the flow label, and a scope identifier
+/// (see [IETF RFC 2553, Section 3.3] for more details).
+///
+/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
+///
+/// The size of a `SocketAddrV6` struct may vary depending on the target operating
+/// system. Do not assume that this type has the same memory layout as the underlying
+/// system representation.
+///
+/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+/// [`IPv6` address]: Ipv6Addr
+///
+/// # Examples
+///
+/// ```
+/// use std::net::{Ipv6Addr, SocketAddrV6};
+///
+/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+///
+/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
+/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
+/// assert_eq!(socket.port(), 8080);
+/// ```
+#[derive(Copy, Clone, Eq, PartialEq)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SocketAddrV6 {
+    ip: Ipv6Addr,
+    port: u16,
+    flowinfo: u32,
+    scope_id: u32,
+}
+
+impl SocketAddr {
+    /// Creates a new socket address from an [IP address] and a port number.
+    ///
+    /// [IP address]: IpAddr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
+    #[stable(feature = "ip_addr", since = "1.7.0")]
+    #[must_use]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
+        match ip {
+            IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
+            IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
+        }
+    }
+
+    /// Returns the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
+    /// ```
+    #[must_use]
+    #[stable(feature = "ip_addr", since = "1.7.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn ip(&self) -> IpAddr {
+        match *self {
+            SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
+            SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
+        }
+    }
+
+    /// Changes the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
+    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_ip(&mut self, new_ip: IpAddr) {
+        // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
+        match (self, new_ip) {
+            (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
+            (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip),
+            (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()),
+        }
+    }
+
+    /// Returns the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn port(&self) -> u16 {
+        match *self {
+            SocketAddr::V4(ref a) => a.port(),
+            SocketAddr::V6(ref a) => a.port(),
+        }
+    }
+
+    /// Changes the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// socket.set_port(1025);
+    /// assert_eq!(socket.port(), 1025);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        match *self {
+            SocketAddr::V4(ref mut a) => a.set_port(new_port),
+            SocketAddr::V6(ref mut a) => a.set_port(new_port),
+        }
+    }
+
+    /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
+    /// [`IPv4` address], and [`false`] otherwise.
+    ///
+    /// [IP address]: IpAddr
+    /// [`IPv4` address]: IpAddr::V4
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
+    /// assert_eq!(socket.is_ipv4(), true);
+    /// assert_eq!(socket.is_ipv6(), false);
+    /// ```
+    #[must_use]
+    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn is_ipv4(&self) -> bool {
+        matches!(*self, SocketAddr::V4(_))
+    }
+
+    /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
+    /// [`IPv6` address], and [`false`] otherwise.
+    ///
+    /// [IP address]: IpAddr
+    /// [`IPv6` address]: IpAddr::V6
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
+    ///
+    /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
+    /// assert_eq!(socket.is_ipv4(), false);
+    /// assert_eq!(socket.is_ipv6(), true);
+    /// ```
+    #[must_use]
+    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn is_ipv6(&self) -> bool {
+        matches!(*self, SocketAddr::V6(_))
+    }
+}
+
+impl SocketAddrV4 {
+    /// Creates a new socket address from an [`IPv4` address] and a port number.
+    ///
+    /// [`IPv4` address]: Ipv4Addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
+        SocketAddrV4 { ip, port }
+    }
+
+    /// Returns the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn ip(&self) -> &Ipv4Addr {
+        &self.ip
+    }
+
+    /// Changes the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
+    /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
+        self.ip = new_ip;
+    }
+
+    /// Returns the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn port(&self) -> u16 {
+        self.port
+    }
+
+    /// Changes the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// socket.set_port(4242);
+    /// assert_eq!(socket.port(), 4242);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        self.port = new_port;
+    }
+}
+
+impl SocketAddrV6 {
+    /// Creates a new socket address from an [`IPv6` address], a 16-bit port number,
+    /// and the `flowinfo` and `scope_id` fields.
+    ///
+    /// For more information on the meaning and layout of the `flowinfo` and `scope_id`
+    /// parameters, see [IETF RFC 2553, Section 3.3].
+    ///
+    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+    /// [`IPv6` address]: Ipv6Addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[must_use]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
+        SocketAddrV6 { ip, port, flowinfo, scope_id }
+    }
+
+    /// Returns the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn ip(&self) -> &Ipv6Addr {
+        &self.ip
+    }
+
+    /// Changes the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+    /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
+        self.ip = new_ip;
+    }
+
+    /// Returns the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn port(&self) -> u16 {
+        self.port
+    }
+
+    /// Changes the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// socket.set_port(4242);
+    /// assert_eq!(socket.port(), 4242);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_port(&mut self, new_port: u16) {
+        self.port = new_port;
+    }
+
+    /// Returns the flow information associated with this address.
+    ///
+    /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`,
+    /// as specified in [IETF RFC 2553, Section 3.3].
+    /// It combines information about the flow label and the traffic class as specified
+    /// in [IETF RFC 2460], respectively [Section 6] and [Section 7].
+    ///
+    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+    /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460
+    /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6
+    /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+    /// assert_eq!(socket.flowinfo(), 10);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn flowinfo(&self) -> u32 {
+        self.flowinfo
+    }
+
+    /// Changes the flow information associated with this socket address.
+    ///
+    /// See [`SocketAddrV6::flowinfo`]'s documentation for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+    /// socket.set_flowinfo(56);
+    /// assert_eq!(socket.flowinfo(), 56);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
+        self.flowinfo = new_flowinfo;
+    }
+
+    /// Returns the scope ID associated with this address.
+    ///
+    /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`,
+    /// as specified in [IETF RFC 2553, Section 3.3].
+    ///
+    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+    /// assert_eq!(socket.scope_id(), 78);
+    /// ```
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
+    pub const fn scope_id(&self) -> u32 {
+        self.scope_id
+    }
+
+    /// Changes the scope ID associated with this socket address.
+    ///
+    /// See [`SocketAddrV6::scope_id`]'s documentation for more details.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+    /// socket.set_scope_id(42);
+    /// assert_eq!(socket.scope_id(), 42);
+    /// ```
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    pub fn set_scope_id(&mut self, new_scope_id: u32) {
+        self.scope_id = new_scope_id;
+    }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<SocketAddrV4> for SocketAddr {
+    /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
+    fn from(sock4: SocketAddrV4) -> SocketAddr {
+        SocketAddr::V4(sock4)
+    }
+}
+
+#[stable(feature = "ip_from_ip", since = "1.16.0")]
+impl From<SocketAddrV6> for SocketAddr {
+    /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
+    fn from(sock6: SocketAddrV6) -> SocketAddr {
+        SocketAddr::V6(sock6)
+    }
+}
+
+#[stable(feature = "addr_from_into_ip", since = "1.17.0")]
+impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
+    /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`].
+    ///
+    /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`]
+    /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`].
+    ///
+    /// `u16` is treated as port of the newly created [`SocketAddr`].
+    fn from(pieces: (I, u16)) -> SocketAddr {
+        SocketAddr::new(pieces.0.into(), pieces.1)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddr {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            SocketAddr::V4(ref a) => a.fmt(f),
+            SocketAddr::V6(ref a) => a.fmt(f),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddrV4 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // If there are no alignment requirements, write the socket address directly to `f`.
+        // Otherwise, write it to a local buffer and then use `f.pad`.
+        if f.precision().is_none() && f.width().is_none() {
+            write!(f, "{}:{}", self.ip(), self.port())
+        } else {
+            const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536";
+
+            let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new();
+            // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail.
+            write!(buf, "{}:{}", self.ip(), self.port()).unwrap();
+
+            f.pad(buf.as_str())
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddrV4 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddrV6 {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // If there are no alignment requirements, write the socket address directly to `f`.
+        // Otherwise, write it to a local buffer and then use `f.pad`.
+        if f.precision().is_none() && f.width().is_none() {
+            match self.scope_id() {
+                0 => write!(f, "[{}]:{}", self.ip(), self.port()),
+                scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
+            }
+        } else {
+            const LONGEST_IPV6_SOCKET_ADDR: &str =
+                "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536";
+
+            let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new();
+            match self.scope_id() {
+                0 => write!(buf, "[{}]:{}", self.ip(), self.port()),
+                scope_id => write!(buf, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
+            }
+            // Buffer is long enough for the longest possible IPv6 socket address, so this should never fail.
+            .unwrap();
+
+            f.pad(buf.as_str())
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for SocketAddrV6 {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl PartialOrd for SocketAddrV4 {
+    fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl PartialOrd for SocketAddrV6 {
+    fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl Ord for SocketAddrV4 {
+    fn cmp(&self, other: &SocketAddrV4) -> Ordering {
+        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
+    }
+}
+
+#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
+impl Ord for SocketAddrV6 {
+    fn cmp(&self, other: &SocketAddrV6) -> Ordering {
+        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for SocketAddrV4 {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        (self.port, self.ip).hash(s)
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl hash::Hash for SocketAddrV6 {
+    fn hash<H: hash::Hasher>(&self, s: &mut H) {
+        (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
+    }
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 42a26ae1675..3947a64e5c6 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -66,6 +66,7 @@
 #![feature(try_trait_v2)]
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
+#![feature(ip)]
 #![feature(iter_advance_by)]
 #![feature(iter_array_chunks)]
 #![feature(iter_collect_into)]
@@ -77,6 +78,9 @@
 #![feature(iter_repeat_n)]
 #![feature(iterator_try_collect)]
 #![feature(iterator_try_reduce)]
+#![feature(const_ip)]
+#![feature(const_ipv4)]
+#![feature(const_ipv6)]
 #![feature(const_mut_refs)]
 #![feature(const_pin)]
 #![feature(const_waker)]
@@ -135,6 +139,7 @@ mod lazy;
 mod macros;
 mod manually_drop;
 mod mem;
+mod net;
 mod nonzero;
 mod num;
 mod ops;
diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs
new file mode 100644
index 00000000000..5a6ac08c088
--- /dev/null
+++ b/library/core/tests/net/ip_addr.rs
@@ -0,0 +1,1035 @@
+use super::{sa4, sa6};
+use core::net::{
+    IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope, SocketAddr, SocketAddrV4, SocketAddrV6,
+};
+use core::str::FromStr;
+
+#[test]
+fn test_from_str_ipv4() {
+    assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
+    assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
+    assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
+
+    // out of range
+    let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // too short
+    let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
+    assert_eq!(None, none);
+    // too long
+    let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
+    assert_eq!(None, none);
+    // no number between dots
+    let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
+    assert_eq!(None, none);
+    // octal
+    let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok();
+    assert_eq!(None, none);
+    // octal zero
+    let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok();
+    assert_eq!(None, none);
+    let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_ipv6() {
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
+
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
+
+    assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse());
+
+    // too long group
+    let none: Option<Ipv6Addr> = "::00000".parse().ok();
+    assert_eq!(None, none);
+    // too short
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
+    assert_eq!(None, none);
+    // too long
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
+    assert_eq!(None, none);
+    // triple colon
+    let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
+    assert_eq!(None, none);
+    // two double colons
+    let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
+    assert_eq!(None, none);
+    // `::` indicating zero groups of zeros
+    let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_ipv4_in_ipv6() {
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse());
+    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse());
+    assert_eq!(
+        Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
+        "64:ff9b::192.0.2.33".parse()
+    );
+    assert_eq!(
+        Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
+        "2001:db8:122:c000:2:2100:192.0.2.33".parse()
+    );
+
+    // colon after v4
+    let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
+    assert_eq!(None, none);
+    // not enough groups
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // too many groups
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn test_from_str_socket_addr() {
+    assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
+    assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
+    assert_eq!(
+        Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
+        "[2a02:6b8:0:1::1]:53".parse()
+    );
+    assert_eq!(
+        Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)),
+        "[2a02:6b8:0:1::1]:53".parse()
+    );
+    assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse());
+    assert_eq!(
+        Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)),
+        "[::127.0.0.1]:22".parse()
+    );
+
+    // without port
+    let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
+    assert_eq!(None, none);
+    // without port
+    let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
+    assert_eq!(None, none);
+    // wrong brackets around v4
+    let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
+    assert_eq!(None, none);
+    // port out of range
+    let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
+    assert_eq!(None, none);
+}
+
+#[test]
+fn ipv4_addr_to_string() {
+    assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
+    // Short address
+    assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
+    // Long address
+    assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
+
+    // Test padding
+    assert_eq!(format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1         ");
+    assert_eq!(format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), "         1.1.1.1");
+}
+
+#[test]
+fn ipv6_addr_to_string() {
+    // ipv4-mapped address
+    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
+    assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
+
+    // ipv4-compatible address
+    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
+    assert_eq!(a1.to_string(), "::192.0.2.128");
+
+    // v6 address with no zero segments
+    assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
+
+    // longest possible IPv6 length
+    assert_eq!(
+        Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(),
+        "1111:2222:3333:4444:5555:6666:7777:8888"
+    );
+    // padding
+    assert_eq!(format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8     ");
+    assert_eq!(format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "     1:2:3:4:5:6:7:8");
+
+    // reduce a single run of zeros
+    assert_eq!(
+        "ae::ffff:102:304",
+        Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()
+    );
+
+    // don't reduce just a single zero segment
+    assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
+
+    // 'any' address
+    assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+    // loopback address
+    assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
+
+    // ends in zeros
+    assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+    // two runs of zeros, second one is longer
+    assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
+
+    // two runs of zeros, equal length
+    assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
+
+    // don't prefix `0x` to each segment in `dbg!`.
+    assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)));
+}
+
+#[test]
+fn ipv4_to_ipv6() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
+        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()
+    );
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
+        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()
+    );
+}
+
+#[test]
+fn ipv6_to_ipv4_mapped() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None);
+}
+
+#[test]
+fn ipv6_to_ipv4() {
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
+    );
+    assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None);
+}
+
+#[test]
+fn ip_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            IpAddr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr) => {
+            check!($s, 0);
+        };
+
+        ($s:expr, $mask:expr) => {{
+            let unspec: u8 = 1 << 0;
+            let loopback: u8 = 1 << 1;
+            let global: u8 = 1 << 2;
+            let multicast: u8 = 1 << 3;
+            let doc: u8 = 1 << 4;
+            let benchmarking: u8 = 1 << 5;
+
+            if ($mask & unspec) == unspec {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+
+            if ($mask & multicast) == multicast {
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(!ip!($s).is_multicast());
+            }
+
+            if ($mask & doc) == doc {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+
+            if ($mask & benchmarking) == benchmarking {
+                assert!(ip!($s).is_benchmarking());
+            } else {
+                assert!(!ip!($s).is_benchmarking());
+            }
+        }};
+    }
+
+    let unspec: u8 = 1 << 0;
+    let loopback: u8 = 1 << 1;
+    let global: u8 = 1 << 2;
+    let multicast: u8 = 1 << 3;
+    let doc: u8 = 1 << 4;
+    let benchmarking: u8 = 1 << 5;
+
+    check!("0.0.0.0", unspec);
+    check!("0.0.0.1");
+    check!("0.1.0.0");
+    check!("10.9.8.7");
+    check!("127.1.2.3", loopback);
+    check!("172.31.254.253");
+    check!("169.254.253.242");
+    check!("192.0.2.183", doc);
+    check!("192.1.2.183", global);
+    check!("192.168.254.253");
+    check!("198.51.100.0", doc);
+    check!("203.0.113.0", doc);
+    check!("203.2.113.0", global);
+    check!("224.0.0.0", global | multicast);
+    check!("239.255.255.255", global | multicast);
+    check!("255.255.255.255");
+    // make sure benchmarking addresses are not global
+    check!("198.18.0.0", benchmarking);
+    check!("198.18.54.2", benchmarking);
+    check!("198.19.255.255", benchmarking);
+    // make sure addresses reserved for protocol assignment are not global
+    check!("192.0.0.0");
+    check!("192.0.0.255");
+    check!("192.0.0.100");
+    // make sure reserved addresses are not global
+    check!("240.0.0.0");
+    check!("251.54.1.76");
+    check!("254.255.255.255");
+    // make sure shared addresses are not global
+    check!("100.64.0.0");
+    check!("100.127.255.255");
+    check!("100.100.100.0");
+
+    check!("::", unspec);
+    check!("::1", loopback);
+    check!("::0.0.0.2", global);
+    check!("1::", global);
+    check!("fc00::");
+    check!("fdff:ffff::");
+    check!("fe80:ffff::");
+    check!("febf:ffff::");
+    check!("fec0::", global);
+    check!("ff01::", global | multicast);
+    check!("ff02::", global | multicast);
+    check!("ff03::", global | multicast);
+    check!("ff04::", global | multicast);
+    check!("ff05::", global | multicast);
+    check!("ff08::", global | multicast);
+    check!("ff0e::", global | multicast);
+    check!("2001:db8:85a3::8a2e:370:7334", doc);
+    check!("2001:2::ac32:23ff:21", benchmarking);
+    check!("102:304:506:708:90a:b0c:d0e:f10", global);
+}
+
+#[test]
+fn ipv4_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            Ipv4Addr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr) => {
+            check!($s, 0);
+        };
+
+        ($s:expr, $mask:expr) => {{
+            let unspec: u16 = 1 << 0;
+            let loopback: u16 = 1 << 1;
+            let private: u16 = 1 << 2;
+            let link_local: u16 = 1 << 3;
+            let global: u16 = 1 << 4;
+            let multicast: u16 = 1 << 5;
+            let broadcast: u16 = 1 << 6;
+            let documentation: u16 = 1 << 7;
+            let benchmarking: u16 = 1 << 8;
+            let reserved: u16 = 1 << 10;
+            let shared: u16 = 1 << 11;
+
+            if ($mask & unspec) == unspec {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+
+            if ($mask & private) == private {
+                assert!(ip!($s).is_private());
+            } else {
+                assert!(!ip!($s).is_private());
+            }
+
+            if ($mask & link_local) == link_local {
+                assert!(ip!($s).is_link_local());
+            } else {
+                assert!(!ip!($s).is_link_local());
+            }
+
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+
+            if ($mask & multicast) == multicast {
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(!ip!($s).is_multicast());
+            }
+
+            if ($mask & broadcast) == broadcast {
+                assert!(ip!($s).is_broadcast());
+            } else {
+                assert!(!ip!($s).is_broadcast());
+            }
+
+            if ($mask & documentation) == documentation {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+
+            if ($mask & benchmarking) == benchmarking {
+                assert!(ip!($s).is_benchmarking());
+            } else {
+                assert!(!ip!($s).is_benchmarking());
+            }
+
+            if ($mask & reserved) == reserved {
+                assert!(ip!($s).is_reserved());
+            } else {
+                assert!(!ip!($s).is_reserved());
+            }
+
+            if ($mask & shared) == shared {
+                assert!(ip!($s).is_shared());
+            } else {
+                assert!(!ip!($s).is_shared());
+            }
+        }};
+    }
+
+    let unspec: u16 = 1 << 0;
+    let loopback: u16 = 1 << 1;
+    let private: u16 = 1 << 2;
+    let link_local: u16 = 1 << 3;
+    let global: u16 = 1 << 4;
+    let multicast: u16 = 1 << 5;
+    let broadcast: u16 = 1 << 6;
+    let documentation: u16 = 1 << 7;
+    let benchmarking: u16 = 1 << 8;
+    let reserved: u16 = 1 << 10;
+    let shared: u16 = 1 << 11;
+
+    check!("0.0.0.0", unspec);
+    check!("0.0.0.1");
+    check!("0.1.0.0");
+    check!("10.9.8.7", private);
+    check!("127.1.2.3", loopback);
+    check!("172.31.254.253", private);
+    check!("169.254.253.242", link_local);
+    check!("192.0.2.183", documentation);
+    check!("192.1.2.183", global);
+    check!("192.168.254.253", private);
+    check!("198.51.100.0", documentation);
+    check!("203.0.113.0", documentation);
+    check!("203.2.113.0", global);
+    check!("224.0.0.0", global | multicast);
+    check!("239.255.255.255", global | multicast);
+    check!("255.255.255.255", broadcast);
+    check!("198.18.0.0", benchmarking);
+    check!("198.18.54.2", benchmarking);
+    check!("198.19.255.255", benchmarking);
+    check!("192.0.0.0");
+    check!("192.0.0.255");
+    check!("192.0.0.100");
+    check!("240.0.0.0", reserved);
+    check!("251.54.1.76", reserved);
+    check!("254.255.255.255", reserved);
+    check!("100.64.0.0", shared);
+    check!("100.127.255.255", shared);
+    check!("100.100.100.0", shared);
+}
+
+#[test]
+fn ipv6_properties() {
+    macro_rules! ip {
+        ($s:expr) => {
+            Ipv6Addr::from_str($s).unwrap()
+        };
+    }
+
+    macro_rules! check {
+        ($s:expr, &[$($octet:expr),*], $mask:expr) => {
+            assert_eq!($s, ip!($s).to_string());
+            let octets = &[$($octet),*];
+            assert_eq!(&ip!($s).octets(), octets);
+            assert_eq!(Ipv6Addr::from(*octets), ip!($s));
+
+            let unspecified: u32 = 1 << 0;
+            let loopback: u32 = 1 << 1;
+            let unique_local: u32 = 1 << 2;
+            let global: u32 = 1 << 3;
+            let unicast_link_local: u32 = 1 << 4;
+            let unicast_global: u32 = 1 << 7;
+            let documentation: u32 = 1 << 8;
+            let benchmarking: u32 = 1 << 16;
+            let multicast_interface_local: u32 = 1 << 9;
+            let multicast_link_local: u32 = 1 << 10;
+            let multicast_realm_local: u32 = 1 << 11;
+            let multicast_admin_local: u32 = 1 << 12;
+            let multicast_site_local: u32 = 1 << 13;
+            let multicast_organization_local: u32 = 1 << 14;
+            let multicast_global: u32 = 1 << 15;
+            let multicast: u32 = multicast_interface_local
+                | multicast_admin_local
+                | multicast_global
+                | multicast_link_local
+                | multicast_realm_local
+                | multicast_site_local
+                | multicast_organization_local;
+
+            if ($mask & unspecified) == unspecified {
+                assert!(ip!($s).is_unspecified());
+            } else {
+                assert!(!ip!($s).is_unspecified());
+            }
+            if ($mask & loopback) == loopback {
+                assert!(ip!($s).is_loopback());
+            } else {
+                assert!(!ip!($s).is_loopback());
+            }
+            if ($mask & unique_local) == unique_local {
+                assert!(ip!($s).is_unique_local());
+            } else {
+                assert!(!ip!($s).is_unique_local());
+            }
+            if ($mask & global) == global {
+                assert!(ip!($s).is_global());
+            } else {
+                assert!(!ip!($s).is_global());
+            }
+            if ($mask & unicast_link_local) == unicast_link_local {
+                assert!(ip!($s).is_unicast_link_local());
+            } else {
+                assert!(!ip!($s).is_unicast_link_local());
+            }
+            if ($mask & unicast_global) == unicast_global {
+                assert!(ip!($s).is_unicast_global());
+            } else {
+                assert!(!ip!($s).is_unicast_global());
+            }
+            if ($mask & documentation) == documentation {
+                assert!(ip!($s).is_documentation());
+            } else {
+                assert!(!ip!($s).is_documentation());
+            }
+            if ($mask & benchmarking) == benchmarking {
+                assert!(ip!($s).is_benchmarking());
+            } else {
+                assert!(!ip!($s).is_benchmarking());
+            }
+            if ($mask & multicast) != 0 {
+                assert!(ip!($s).multicast_scope().is_some());
+                assert!(ip!($s).is_multicast());
+            } else {
+                assert!(ip!($s).multicast_scope().is_none());
+                assert!(!ip!($s).is_multicast());
+            }
+            if ($mask & multicast_interface_local) == multicast_interface_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::InterfaceLocal);
+            }
+            if ($mask & multicast_link_local) == multicast_link_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::LinkLocal);
+            }
+            if ($mask & multicast_realm_local) == multicast_realm_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::RealmLocal);
+            }
+            if ($mask & multicast_admin_local) == multicast_admin_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::AdminLocal);
+            }
+            if ($mask & multicast_site_local) == multicast_site_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::SiteLocal);
+            }
+            if ($mask & multicast_organization_local) == multicast_organization_local {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::OrganizationLocal);
+            }
+            if ($mask & multicast_global) == multicast_global {
+                assert_eq!(ip!($s).multicast_scope().unwrap(),
+                           Ipv6MulticastScope::Global);
+            }
+        }
+    }
+
+    let unspecified: u32 = 1 << 0;
+    let loopback: u32 = 1 << 1;
+    let unique_local: u32 = 1 << 2;
+    let global: u32 = 1 << 3;
+    let unicast_link_local: u32 = 1 << 4;
+    let unicast_global: u32 = 1 << 7;
+    let documentation: u32 = 1 << 8;
+    let benchmarking: u32 = 1 << 16;
+    let multicast_interface_local: u32 = 1 << 9;
+    let multicast_link_local: u32 = 1 << 10;
+    let multicast_realm_local: u32 = 1 << 11;
+    let multicast_admin_local: u32 = 1 << 12;
+    let multicast_site_local: u32 = 1 << 13;
+    let multicast_organization_local: u32 = 1 << 14;
+    let multicast_global: u32 = 1 << 15;
+
+    check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
+
+    check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
+
+    check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global);
+
+    check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
+
+    check!(
+        "::ffff:127.0.0.1",
+        &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
+        unicast_global
+    );
+
+    check!(
+        "64:ff9b:1::",
+        &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_global
+    );
+
+    check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!(
+        "2001:1::1",
+        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:1::2",
+        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:3::",
+        &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:4:112::",
+        &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!(
+        "2001:20::",
+        &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
+    check!(
+        "2001:200::",
+        &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        global | unicast_global
+    );
+
+    check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
+
+    check!(
+        "fdff:ffff::",
+        &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unique_local
+    );
+
+    check!(
+        "fe80:ffff::",
+        &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
+
+    check!(
+        "febf:ffff::",
+        &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
+
+    check!(
+        "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+        &[
+            0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff
+        ],
+        unicast_link_local
+    );
+
+    check!(
+        "fe80::ffff:ffff:ffff:ffff",
+        &[
+            0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff
+        ],
+        unicast_link_local
+    );
+
+    check!(
+        "fe80:0:0:1::",
+        &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_link_local
+    );
+
+    check!(
+        "fec0::",
+        &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        unicast_global | global
+    );
+
+    check!(
+        "ff01::",
+        &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_interface_local | global
+    );
+
+    check!(
+        "ff02::",
+        &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_link_local | global
+    );
+
+    check!(
+        "ff03::",
+        &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_realm_local | global
+    );
+
+    check!(
+        "ff04::",
+        &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_admin_local | global
+    );
+
+    check!(
+        "ff05::",
+        &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_site_local | global
+    );
+
+    check!(
+        "ff08::",
+        &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_organization_local | global
+    );
+
+    check!(
+        "ff0e::",
+        &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+        multicast_global | global
+    );
+
+    check!(
+        "2001:db8:85a3::8a2e:370:7334",
+        &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
+        documentation
+    );
+
+    check!(
+        "2001:2::ac32:23ff:21",
+        &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
+        benchmarking
+    );
+
+    check!(
+        "102:304:506:708:90a:b0c:d0e:f10",
+        &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
+        global | unicast_global
+    );
+}
+
+#[test]
+fn test_ipv4_to_int() {
+    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+    assert_eq!(u32::from(a), 0x11223344);
+}
+
+#[test]
+fn test_int_to_ipv4() {
+    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
+    assert_eq!(Ipv4Addr::from(0x11223344), a);
+}
+
+#[test]
+fn test_ipv6_to_int() {
+    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+    assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
+}
+
+#[test]
+fn test_int_to_ipv6() {
+    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
+    assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
+}
+
+#[test]
+fn ipv4_from_constructors() {
+    assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
+    assert!(Ipv4Addr::LOCALHOST.is_loopback());
+    assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
+    assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
+    assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
+    assert!(Ipv4Addr::BROADCAST.is_broadcast());
+}
+
+#[test]
+fn ipv6_from_constructors() {
+    assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    assert!(Ipv6Addr::LOCALHOST.is_loopback());
+    assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
+    assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
+}
+
+#[test]
+fn ipv4_from_octets() {
+    assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
+}
+
+#[test]
+fn ipv6_from_segments() {
+    let from_u16s =
+        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+    let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
+    assert_eq!(new, from_u16s);
+}
+
+#[test]
+fn ipv6_from_octets() {
+    let from_u16s =
+        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
+    let from_u8s = Ipv6Addr::from([
+        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
+        0xff,
+    ]);
+    assert_eq!(from_u16s, from_u8s);
+}
+
+#[test]
+fn cmp() {
+    let v41 = Ipv4Addr::new(100, 64, 3, 3);
+    let v42 = Ipv4Addr::new(192, 0, 2, 2);
+    let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
+    let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
+    assert!(v41 < v42);
+    assert!(v61 < v62);
+
+    assert_eq!(v41, IpAddr::V4(v41));
+    assert_eq!(v61, IpAddr::V6(v61));
+    assert!(v41 != IpAddr::V4(v42));
+    assert!(v61 != IpAddr::V6(v62));
+
+    assert!(v41 < IpAddr::V4(v42));
+    assert!(v61 < IpAddr::V6(v62));
+    assert!(IpAddr::V4(v41) < v42);
+    assert!(IpAddr::V6(v61) < v62);
+
+    assert!(v41 < IpAddr::V6(v61));
+    assert!(IpAddr::V4(v41) < v61);
+}
+
+#[test]
+fn is_v4() {
+    let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
+    assert!(ip.is_ipv4());
+    assert!(!ip.is_ipv6());
+}
+
+#[test]
+fn is_v6() {
+    let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
+    assert!(!ip.is_ipv4());
+    assert!(ip.is_ipv6());
+}
+
+#[test]
+fn ipv4_const() {
+    // test that the methods of `Ipv4Addr` are usable in a const context
+
+    const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
+    assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST);
+
+    const OCTETS: [u8; 4] = IP_ADDRESS.octets();
+    assert_eq!(OCTETS, [127, 0, 0, 1]);
+
+    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
+    assert!(!IS_UNSPECIFIED);
+
+    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
+    assert!(IS_LOOPBACK);
+
+    const IS_PRIVATE: bool = IP_ADDRESS.is_private();
+    assert!(!IS_PRIVATE);
+
+    const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local();
+    assert!(!IS_LINK_LOCAL);
+
+    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
+    assert!(!IS_GLOBAL);
+
+    const IS_SHARED: bool = IP_ADDRESS.is_shared();
+    assert!(!IS_SHARED);
+
+    const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
+    assert!(!IS_BENCHMARKING);
+
+    const IS_RESERVED: bool = IP_ADDRESS.is_reserved();
+    assert!(!IS_RESERVED);
+
+    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
+    assert!(!IS_MULTICAST);
+
+    const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast();
+    assert!(!IS_BROADCAST);
+
+    const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
+    assert!(!IS_DOCUMENTATION);
+
+    const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible();
+    assert_eq!(
+        IP_V6_COMPATIBLE,
+        Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])
+    );
+
+    const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped();
+    assert_eq!(
+        IP_V6_MAPPED,
+        Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])
+    );
+}
+
+#[test]
+fn ipv6_const() {
+    // test that the methods of `Ipv6Addr` are usable in a const context
+
+    const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST);
+
+    const SEGMENTS: [u16; 8] = IP_ADDRESS.segments();
+    assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]);
+
+    const OCTETS: [u8; 16] = IP_ADDRESS.octets();
+    assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
+
+    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
+    assert!(!IS_UNSPECIFIED);
+
+    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
+    assert!(IS_LOOPBACK);
+
+    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
+    assert!(!IS_GLOBAL);
+
+    const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
+    assert!(!IS_UNIQUE_LOCAL);
+
+    const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
+    assert!(!IS_UNICAST_LINK_LOCAL);
+
+    const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
+    assert!(!IS_DOCUMENTATION);
+
+    const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
+    assert!(!IS_BENCHMARKING);
+
+    const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global();
+    assert!(!IS_UNICAST_GLOBAL);
+
+    const MULTICAST_SCOPE: Option<Ipv6MulticastScope> = IP_ADDRESS.multicast_scope();
+    assert_eq!(MULTICAST_SCOPE, None);
+
+    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
+    assert!(!IS_MULTICAST);
+
+    const IP_V4: Option<Ipv4Addr> = IP_ADDRESS.to_ipv4();
+    assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1));
+}
+
+#[test]
+fn ip_const() {
+    // test that the methods of `IpAddr` are usable in a const context
+
+    const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
+
+    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
+    assert!(!IS_UNSPECIFIED);
+
+    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
+    assert!(IS_LOOPBACK);
+
+    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
+    assert!(!IS_GLOBAL);
+
+    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
+    assert!(!IS_MULTICAST);
+
+    const IS_IP_V4: bool = IP_ADDRESS.is_ipv4();
+    assert!(IS_IP_V4);
+
+    const IS_IP_V6: bool = IP_ADDRESS.is_ipv6();
+    assert!(!IS_IP_V6);
+}
+
+#[test]
+fn structural_match() {
+    // test that all IP types can be structurally matched upon
+
+    const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST;
+    match IPV4 {
+        Ipv4Addr::LOCALHOST => {}
+        _ => unreachable!(),
+    }
+
+    const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST;
+    match IPV6 {
+        Ipv6Addr::LOCALHOST => {}
+        _ => unreachable!(),
+    }
+
+    const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
+    match IP {
+        IpAddr::V4(Ipv4Addr::LOCALHOST) => {}
+        _ => unreachable!(),
+    }
+}
diff --git a/library/core/tests/net/mod.rs b/library/core/tests/net/mod.rs
new file mode 100644
index 00000000000..8f17bbe5548
--- /dev/null
+++ b/library/core/tests/net/mod.rs
@@ -0,0 +1,13 @@
+use core::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+
+mod ip_addr;
+mod parser;
+mod socket_addr;
+
+pub fn sa4(a: Ipv4Addr, p: u16) -> SocketAddr {
+    SocketAddr::V4(SocketAddrV4::new(a, p))
+}
+
+pub fn sa6(a: Ipv6Addr, p: u16) -> SocketAddr {
+    SocketAddr::V6(SocketAddrV6::new(a, p, 0, 0))
+}
diff --git a/library/std/src/net/parser/tests.rs b/library/core/tests/net/parser.rs
index 6d2d48ecad0..36b87d7c1f5 100644
--- a/library/std/src/net/parser/tests.rs
+++ b/library/core/tests/net/parser.rs
@@ -1,6 +1,6 @@
 // FIXME: These tests are all excellent candidates for AFL fuzz testing
-use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
-use crate::str::FromStr;
+use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use core::str::FromStr;
 
 const PORT: u16 = 8080;
 const SCOPE_ID: u32 = 1337;
diff --git a/library/core/tests/net/socket_addr.rs b/library/core/tests/net/socket_addr.rs
new file mode 100644
index 00000000000..68c7cd94d32
--- /dev/null
+++ b/library/core/tests/net/socket_addr.rs
@@ -0,0 +1,233 @@
+use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+
+#[test]
+fn ipv4_socket_addr_to_string() {
+    // Shortest possible IPv4 length.
+    assert_eq!(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 0).to_string(), "0.0.0.0:0");
+
+    // Longest possible IPv4 length.
+    assert_eq!(
+        SocketAddrV4::new(Ipv4Addr::new(255, 255, 255, 255), u16::MAX).to_string(),
+        "255.255.255.255:65535"
+    );
+
+    // Test padding.
+    assert_eq!(
+        &format!("{:16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
+        "1.1.1.1:53      "
+    );
+    assert_eq!(
+        &format!("{:>16}", SocketAddrV4::new(Ipv4Addr::new(1, 1, 1, 1), 53)),
+        "      1.1.1.1:53"
+    );
+}
+
+#[test]
+fn ipv6_socket_addr_to_string() {
+    // IPv4-mapped address.
+    assert_eq!(
+        SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280), 8080, 0, 0)
+            .to_string(),
+        "[::ffff:192.0.2.128]:8080"
+    );
+
+    // IPv4-compatible address.
+    assert_eq!(
+        SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280), 8080, 0, 0).to_string(),
+        "[::192.0.2.128]:8080"
+    );
+
+    // IPv6 address with no zero segments.
+    assert_eq!(
+        SocketAddrV6::new(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15), 80, 0, 0).to_string(),
+        "[8:9:a:b:c:d:e:f]:80"
+    );
+
+    // Shortest possible IPv6 length.
+    assert_eq!(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0).to_string(), "[::]:0");
+
+    // Longest possible IPv6 length.
+    assert_eq!(
+        SocketAddrV6::new(
+            Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888),
+            u16::MAX,
+            u32::MAX,
+            u32::MAX,
+        )
+        .to_string(),
+        "[1111:2222:3333:4444:5555:6666:7777:8888%4294967295]:65535"
+    );
+
+    // Test padding.
+    assert_eq!(
+        &format!("{:22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
+        "[1:2:3:4:5:6:7:8]:9   "
+    );
+    assert_eq!(
+        &format!("{:>22}", SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9, 0, 0)),
+        "   [1:2:3:4:5:6:7:8]:9"
+    );
+}
+
+#[test]
+fn set_ip() {
+    fn ip4(low: u8) -> Ipv4Addr {
+        Ipv4Addr::new(77, 88, 21, low)
+    }
+    fn ip6(low: u16) -> Ipv6Addr {
+        Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low)
+    }
+
+    let mut v4 = SocketAddrV4::new(ip4(11), 80);
+    assert_eq!(v4.ip(), &ip4(11));
+    v4.set_ip(ip4(12));
+    assert_eq!(v4.ip(), &ip4(12));
+
+    let mut addr = SocketAddr::V4(v4);
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(12)));
+    addr.set_ip(IpAddr::V4(ip4(13)));
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(13)));
+    addr.set_ip(IpAddr::V6(ip6(14)));
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(14)));
+
+    let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0);
+    assert_eq!(v6.ip(), &ip6(1));
+    v6.set_ip(ip6(2));
+    assert_eq!(v6.ip(), &ip6(2));
+
+    let mut addr = SocketAddr::V6(v6);
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(2)));
+    addr.set_ip(IpAddr::V6(ip6(3)));
+    assert_eq!(addr.ip(), IpAddr::V6(ip6(3)));
+    addr.set_ip(IpAddr::V4(ip4(4)));
+    assert_eq!(addr.ip(), IpAddr::V4(ip4(4)));
+}
+
+#[test]
+fn set_port() {
+    let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80);
+    assert_eq!(v4.port(), 80);
+    v4.set_port(443);
+    assert_eq!(v4.port(), 443);
+
+    let mut addr = SocketAddr::V4(v4);
+    assert_eq!(addr.port(), 443);
+    addr.set_port(8080);
+    assert_eq!(addr.port(), 8080);
+
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0);
+    assert_eq!(v6.port(), 80);
+    v6.set_port(443);
+    assert_eq!(v6.port(), 443);
+
+    let mut addr = SocketAddr::V6(v6);
+    assert_eq!(addr.port(), 443);
+    addr.set_port(8080);
+    assert_eq!(addr.port(), 8080);
+}
+
+#[test]
+fn set_flowinfo() {
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0);
+    assert_eq!(v6.flowinfo(), 10);
+    v6.set_flowinfo(20);
+    assert_eq!(v6.flowinfo(), 20);
+}
+
+#[test]
+fn set_scope_id() {
+    let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10);
+    assert_eq!(v6.scope_id(), 10);
+    v6.set_scope_id(20);
+    assert_eq!(v6.scope_id(), 20);
+}
+
+#[test]
+fn is_v4() {
+    let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
+    assert!(v4.is_ipv4());
+    assert!(!v4.is_ipv6());
+}
+
+#[test]
+fn is_v6() {
+    let v6 = SocketAddr::V6(SocketAddrV6::new(
+        Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1),
+        80,
+        10,
+        0,
+    ));
+    assert!(!v6.is_ipv4());
+    assert!(v6.is_ipv6());
+}
+
+#[test]
+fn socket_v4_to_str() {
+    let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080);
+
+    assert_eq!(format!("{socket}"), "192.168.0.1:8080");
+    assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080    ");
+    assert_eq!(format!("{socket:>20}"), "    192.168.0.1:8080");
+    assert_eq!(format!("{socket:^20}"), "  192.168.0.1:8080  ");
+    assert_eq!(format!("{socket:.10}"), "192.168.0.");
+}
+
+#[test]
+fn socket_v6_to_str() {
+    let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0);
+
+    assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53");
+    assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53    ");
+    assert_eq!(format!("{socket:>24}"), "    [2a02:6b8:0:1::1]:53");
+    assert_eq!(format!("{socket:^24}"), "  [2a02:6b8:0:1::1]:53  ");
+    assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::");
+
+    socket.set_scope_id(5);
+
+    assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53");
+    assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53  ");
+    assert_eq!(format!("{socket:>24}"), "  [2a02:6b8:0:1::1%5]:53");
+    assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 ");
+    assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5");
+}
+
+#[test]
+fn compare() {
+    let v4_1 = "224.120.45.1:23456".parse::<SocketAddrV4>().unwrap();
+    let v4_2 = "224.210.103.5:12345".parse::<SocketAddrV4>().unwrap();
+    let v4_3 = "224.210.103.5:23456".parse::<SocketAddrV4>().unwrap();
+    let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
+    let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
+    let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
+
+    // equality
+    assert_eq!(v4_1, v4_1);
+    assert_eq!(v6_1, v6_1);
+    assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1));
+    assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
+    assert!(v4_1 != v4_2);
+    assert!(v6_1 != v6_2);
+
+    // compare different addresses
+    assert!(v4_1 < v4_2);
+    assert!(v6_1 < v6_2);
+    assert!(v4_2 > v4_1);
+    assert!(v6_2 > v6_1);
+
+    // compare the same address with different ports
+    assert!(v4_2 < v4_3);
+    assert!(v6_2 < v6_3);
+    assert!(v4_3 > v4_2);
+    assert!(v6_3 > v6_2);
+
+    // compare different addresses with the same port
+    assert!(v4_1 < v4_3);
+    assert!(v6_1 < v6_3);
+    assert!(v4_3 > v4_1);
+    assert!(v6_3 > v6_1);
+
+    // compare with an inferred right-hand side
+    assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
+    assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());
+    assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap());
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 363a2667174..b62f3ad29d3 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -232,6 +232,7 @@
     all(target_vendor = "fortanix", target_env = "sgx"),
     feature(slice_index_methods, coerce_unsized, sgx_platform)
 )]
+#![cfg_attr(windows, feature(round_char_boundary))]
 //
 // Language features:
 #![feature(alloc_error_handler)]
@@ -287,6 +288,8 @@
 #![feature(float_next_up_down)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
+#![feature(ip)]
+#![feature(ip_in_core)]
 #![feature(is_some_and)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_write_slice)]
diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs
index 07f08c1b586..e167fbd1b9c 100644
--- a/library/std/src/net/ip_addr.rs
+++ b/library/std/src/net/ip_addr.rs
@@ -2,2101 +2,40 @@
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
 
-use crate::cmp::Ordering;
-use crate::fmt::{self, Write};
-use crate::mem::transmute;
 use crate::sys::net::netc as c;
 use crate::sys_common::{FromInner, IntoInner};
 
-use super::display_buffer::DisplayBuffer;
-
-/// An IP address, either IPv4 or IPv6.
-///
-/// This enum can contain either an [`Ipv4Addr`] or an [`Ipv6Addr`], see their
-/// respective documentation for more details.
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-///
-/// let localhost_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
-/// let localhost_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-///
-/// assert_eq!("127.0.0.1".parse(), Ok(localhost_v4));
-/// assert_eq!("::1".parse(), Ok(localhost_v6));
-///
-/// assert_eq!(localhost_v4.is_ipv6(), false);
-/// assert_eq!(localhost_v4.is_ipv4(), true);
-/// ```
-#[cfg_attr(not(test), rustc_diagnostic_item = "IpAddr")]
 #[stable(feature = "ip_addr", since = "1.7.0")]
-#[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
-pub enum IpAddr {
-    /// An IPv4 address.
-    #[stable(feature = "ip_addr", since = "1.7.0")]
-    V4(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv4Addr),
-    /// An IPv6 address.
-    #[stable(feature = "ip_addr", since = "1.7.0")]
-    V6(#[stable(feature = "ip_addr", since = "1.7.0")] Ipv6Addr),
-}
+pub use core::net::IpAddr;
 
-/// An IPv4 address.
-///
-/// IPv4 addresses are defined as 32-bit integers in [IETF RFC 791].
-/// They are usually represented as four octets.
-///
-/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
-///
-/// [IETF RFC 791]: https://tools.ietf.org/html/rfc791
-///
-/// # Textual representation
-///
-/// `Ipv4Addr` provides a [`FromStr`] implementation. The four octets are in decimal
-/// notation, divided by `.` (this is called "dot-decimal notation").
-/// Notably, octal numbers (which are indicated with a leading `0`) and hexadecimal numbers (which
-/// are indicated with a leading `0x`) are not allowed per [IETF RFC 6943].
-///
-/// [IETF RFC 6943]: https://tools.ietf.org/html/rfc6943#section-3.1.1
-/// [`FromStr`]: crate::str::FromStr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::Ipv4Addr;
-///
-/// let localhost = Ipv4Addr::new(127, 0, 0, 1);
-/// assert_eq!("127.0.0.1".parse(), Ok(localhost));
-/// assert_eq!(localhost.is_loopback(), true);
-/// assert!("012.004.002.000".parse::<Ipv4Addr>().is_err()); // all octets are in octal
-/// assert!("0000000.0.0.0".parse::<Ipv4Addr>().is_err()); // first octet is a zero in octal
-/// assert!("0xcb.0x0.0x71.0x00".parse::<Ipv4Addr>().is_err()); // all octets are in hex
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct Ipv4Addr {
-    octets: [u8; 4],
-}
+pub use core::net::{Ipv4Addr, Ipv6Addr};
 
-/// An IPv6 address.
-///
-/// IPv6 addresses are defined as 128-bit integers in [IETF RFC 4291].
-/// They are usually represented as eight 16-bit segments.
-///
-/// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-///
-/// # Embedding IPv4 Addresses
-///
-/// See [`IpAddr`] for a type encompassing both IPv4 and IPv6 addresses.
-///
-/// To assist in the transition from IPv4 to IPv6 two types of IPv6 addresses that embed an IPv4 address were defined:
-/// IPv4-compatible and IPv4-mapped addresses. Of these IPv4-compatible addresses have been officially deprecated.
-///
-/// Both types of addresses are not assigned any special meaning by this implementation,
-/// other than what the relevant standards prescribe. This means that an address like `::ffff:127.0.0.1`,
-/// while representing an IPv4 loopback address, is not itself an IPv6 loopback address; only `::1` is.
-/// To handle these so called "IPv4-in-IPv6" addresses, they have to first be converted to their canonical IPv4 address.
-///
-/// ### IPv4-Compatible IPv6 Addresses
-///
-/// IPv4-compatible IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.1], and have been officially deprecated.
-/// The RFC describes the format of an "IPv4-Compatible IPv6 address" as follows:
-///
-/// ```text
-/// |                80 bits               | 16 |      32 bits        |
-/// +--------------------------------------+--------------------------+
-/// |0000..............................0000|0000|    IPv4 address     |
-/// +--------------------------------------+----+---------------------+
-/// ```
-/// So `::a.b.c.d` would be an IPv4-compatible IPv6 address representing the IPv4 address `a.b.c.d`.
-///
-/// To convert from an IPv4 address to an IPv4-compatible IPv6 address, use [`Ipv4Addr::to_ipv6_compatible`].
-/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-compatible IPv6 address to the canonical IPv4 address.
-///
-/// [IETF RFC 4291 Section 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1
-///
-/// ### IPv4-Mapped IPv6 Addresses
-///
-/// IPv4-mapped IPv6 addresses are defined in [IETF RFC 4291 Section 2.5.5.2].
-/// The RFC describes the format of an "IPv4-Mapped IPv6 address" as follows:
-///
-/// ```text
-/// |                80 bits               | 16 |      32 bits        |
-/// +--------------------------------------+--------------------------+
-/// |0000..............................0000|FFFF|    IPv4 address     |
-/// +--------------------------------------+----+---------------------+
-/// ```
-/// So `::ffff:a.b.c.d` would be an IPv4-mapped IPv6 address representing the IPv4 address `a.b.c.d`.
-///
-/// To convert from an IPv4 address to an IPv4-mapped IPv6 address, use [`Ipv4Addr::to_ipv6_mapped`].
-/// Use [`Ipv6Addr::to_ipv4`] to convert an IPv4-mapped IPv6 address to the canonical IPv4 address.
-/// Note that this will also convert the IPv6 loopback address `::1` to `0.0.0.1`. Use
-/// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
-///
-/// [IETF RFC 4291 Section 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
-///
-/// # Textual representation
-///
-/// `Ipv6Addr` provides a [`FromStr`] implementation. There are many ways to represent
-/// an IPv6 address in text, but in general, each segments is written in hexadecimal
-/// notation, and segments are separated by `:`. For more information, see
-/// [IETF RFC 5952].
-///
-/// [`FromStr`]: crate::str::FromStr
-/// [IETF RFC 5952]: https://tools.ietf.org/html/rfc5952
-///
-/// # Examples
-///
-/// ```
-/// use std::net::Ipv6Addr;
-///
-/// let localhost = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
-/// assert_eq!("::1".parse(), Ok(localhost));
-/// assert_eq!(localhost.is_loopback(), true);
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Ipv6Addr {
-    octets: [u8; 16],
-}
-
-/// Scope of an [IPv6 multicast address] as defined in [IETF RFC 7346 section 2].
-///
-/// # Stability Guarantees
-///
-/// Not all possible values for a multicast scope have been assigned.
-/// Future RFCs may introduce new scopes, which will be added as variants to this enum;
-/// because of this the enum is marked as `#[non_exhaustive]`.
-///
-/// # Examples
-/// ```
-/// #![feature(ip)]
-///
-/// use std::net::Ipv6Addr;
-/// use std::net::Ipv6MulticastScope::*;
-///
-/// // An IPv6 multicast address with global scope (`ff0e::`).
-/// let address = Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0);
-///
-/// // Will print "Global scope".
-/// match address.multicast_scope() {
-///     Some(InterfaceLocal) => println!("Interface-Local scope"),
-///     Some(LinkLocal) => println!("Link-Local scope"),
-///     Some(RealmLocal) => println!("Realm-Local scope"),
-///     Some(AdminLocal) => println!("Admin-Local scope"),
-///     Some(SiteLocal) => println!("Site-Local scope"),
-///     Some(OrganizationLocal) => println!("Organization-Local scope"),
-///     Some(Global) => println!("Global scope"),
-///     Some(_) => println!("Unknown scope"),
-///     None => println!("Not a multicast address!")
-/// }
-///
-/// ```
-///
-/// [IPv6 multicast address]: Ipv6Addr
-/// [IETF RFC 7346 section 2]: https://tools.ietf.org/html/rfc7346#section-2
-#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
 #[unstable(feature = "ip", issue = "27709")]
-#[non_exhaustive]
-pub enum Ipv6MulticastScope {
-    /// Interface-Local scope.
-    InterfaceLocal,
-    /// Link-Local scope.
-    LinkLocal,
-    /// Realm-Local scope.
-    RealmLocal,
-    /// Admin-Local scope.
-    AdminLocal,
-    /// Site-Local scope.
-    SiteLocal,
-    /// Organization-Local scope.
-    OrganizationLocal,
-    /// Global scope.
-    Global,
-}
-
-impl IpAddr {
-    /// Returns [`true`] for the special 'unspecified' address.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_unspecified()`] and
-    /// [`Ipv6Addr::is_unspecified()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ip_shared", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unspecified(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_unspecified(),
-            IpAddr::V6(ip) => ip.is_unspecified(),
-        }
-    }
-
-    /// Returns [`true`] if this is a loopback address.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_loopback()`] and
-    /// [`Ipv6Addr::is_loopback()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ip_shared", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_loopback(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_loopback(),
-            IpAddr::V6(ip) => ip.is_loopback(),
-        }
-    }
-
-    /// Returns [`true`] if the address appears to be globally routable.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_global()`] and
-    /// [`Ipv6Addr::is_global()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_global(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_global(),
-            IpAddr::V6(ip) => ip.is_global(),
-        }
-    }
-
-    /// Returns [`true`] if this is a multicast address.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_multicast()`] and
-    /// [`Ipv6Addr::is_multicast()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ip_shared", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_multicast(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_multicast(),
-            IpAddr::V6(ip) => ip.is_multicast(),
-        }
-    }
-
-    /// Returns [`true`] if this address is in a range designated for documentation.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_documentation()`] and
-    /// [`Ipv6Addr::is_documentation()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_documentation(), true);
-    /// assert_eq!(
-    ///     IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_documentation(),
-    ///     true
-    /// );
-    /// ```
-    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_documentation(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_documentation(),
-            IpAddr::V6(ip) => ip.is_documentation(),
-        }
-    }
-
-    /// Returns [`true`] if this address is in a range designated for benchmarking.
-    ///
-    /// See the documentation for [`Ipv4Addr::is_benchmarking()`] and
-    /// [`Ipv6Addr::is_benchmarking()`] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(198, 19, 255, 255)).is_benchmarking(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0)).is_benchmarking(), true);
-    /// ```
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_benchmarking(&self) -> bool {
-        match self {
-            IpAddr::V4(ip) => ip.is_benchmarking(),
-            IpAddr::V6(ip) => ip.is_benchmarking(),
-        }
-    }
-
-    /// Returns [`true`] if this address is an [`IPv4` address], and [`false`]
-    /// otherwise.
-    ///
-    /// [`IPv4` address]: IpAddr::V4
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv4(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv4(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_ipv4(&self) -> bool {
-        matches!(self, IpAddr::V4(_))
-    }
-
-    /// Returns [`true`] if this address is an [`IPv6` address], and [`false`]
-    /// otherwise.
-    ///
-    /// [`IPv6` address]: IpAddr::V6
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(203, 0, 113, 6)).is_ipv6(), false);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0)).is_ipv6(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "ipaddr_checker", since = "1.16.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_ipv6(&self) -> bool {
-        matches!(self, IpAddr::V6(_))
-    }
-
-    /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped IPv6 addresses, otherwise it
-    /// return `self` as-is.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).to_canonical().is_loopback(), true);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).is_loopback(), false);
-    /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1)).to_canonical().is_loopback(), true);
-    /// ```
-    #[inline]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    pub const fn to_canonical(&self) -> IpAddr {
-        match self {
-            &v4 @ IpAddr::V4(_) => v4,
-            IpAddr::V6(v6) => v6.to_canonical(),
-        }
-    }
-}
-
-impl Ipv4Addr {
-    /// Creates a new IPv4 address from four eight-bit octets.
-    ///
-    /// The result will represent the IP address `a`.`b`.`c`.`d`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[inline]
-    pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
-        Ipv4Addr { octets: [a, b, c, d] }
-    }
-
-    /// An IPv4 address with the address pointing to localhost: `127.0.0.1`
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::LOCALHOST;
-    /// assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1));
-    /// ```
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const LOCALHOST: Self = Ipv4Addr::new(127, 0, 0, 1);
-
-    /// An IPv4 address representing an unspecified address: `0.0.0.0`
-    ///
-    /// This corresponds to the constant `INADDR_ANY` in other languages.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::UNSPECIFIED;
-    /// assert_eq!(addr, Ipv4Addr::new(0, 0, 0, 0));
-    /// ```
-    #[doc(alias = "INADDR_ANY")]
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const UNSPECIFIED: Self = Ipv4Addr::new(0, 0, 0, 0);
-
-    /// An IPv4 address representing the broadcast address: `255.255.255.255`
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::BROADCAST;
-    /// assert_eq!(addr, Ipv4Addr::new(255, 255, 255, 255));
-    /// ```
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const BROADCAST: Self = Ipv4Addr::new(255, 255, 255, 255);
-
-    /// Returns the four eight-bit integers that make up this address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
-    /// assert_eq!(addr.octets(), [127, 0, 0, 1]);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[inline]
-    pub const fn octets(&self) -> [u8; 4] {
-        self.octets
-    }
-
-    /// Returns [`true`] for the special 'unspecified' address (`0.0.0.0`).
-    ///
-    /// This property is defined in _UNIX Network Programming, Second Edition_,
-    /// W. Richard Stevens, p. 891; see also [ip7].
-    ///
-    /// [ip7]: https://man7.org/linux/man-pages/man7/ip.7.html
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(0, 0, 0, 0).is_unspecified(), true);
-    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
-    #[stable(feature = "ip_shared", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unspecified(&self) -> bool {
-        u32::from_be_bytes(self.octets) == 0
-    }
-
-    /// Returns [`true`] if this is a loopback address (`127.0.0.0/8`).
-    ///
-    /// This property is defined by [IETF RFC 1122].
-    ///
-    /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true);
-    /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_loopback(&self) -> bool {
-        self.octets()[0] == 127
-    }
-
-    /// Returns [`true`] if this is a private address.
-    ///
-    /// The private address ranges are defined in [IETF RFC 1918] and include:
-    ///
-    ///  - `10.0.0.0/8`
-    ///  - `172.16.0.0/12`
-    ///  - `192.168.0.0/16`
-    ///
-    /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(10, 0, 0, 1).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(10, 10, 10, 10).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 10).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(172, 29, 45, 14).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(172, 32, 0, 2).is_private(), false);
-    /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true);
-    /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_private(&self) -> bool {
-        match self.octets() {
-            [10, ..] => true,
-            [172, b, ..] if b >= 16 && b <= 31 => true,
-            [192, 168, ..] => true,
-            _ => false,
-        }
-    }
-
-    /// Returns [`true`] if the address is link-local (`169.254.0.0/16`).
-    ///
-    /// This property is defined by [IETF RFC 3927].
-    ///
-    /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(169, 254, 0, 0).is_link_local(), true);
-    /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true);
-    /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_link_local(&self) -> bool {
-        matches!(self.octets(), [169, 254, ..])
-    }
-
-    /// Returns [`true`] if the address appears to be globally reachable
-    /// as specified by the [IANA IPv4 Special-Purpose Address Registry].
-    /// Whether or not an address is practically reachable will depend on your network configuration.
-    ///
-    /// Most IPv4 addresses are globally reachable;
-    /// unless they are specifically defined as *not* globally reachable.
-    ///
-    /// Non-exhaustive list of notable addresses that are not globally reachable:
-    ///
-    /// - The [unspecified address] ([`is_unspecified`](Ipv4Addr::is_unspecified))
-    /// - Addresses reserved for private use ([`is_private`](Ipv4Addr::is_private))
-    /// - Addresses in the shared address space ([`is_shared`](Ipv4Addr::is_shared))
-    /// - Loopback addresses ([`is_loopback`](Ipv4Addr::is_loopback))
-    /// - Link-local addresses ([`is_link_local`](Ipv4Addr::is_link_local))
-    /// - Addresses reserved for documentation ([`is_documentation`](Ipv4Addr::is_documentation))
-    /// - Addresses reserved for benchmarking ([`is_benchmarking`](Ipv4Addr::is_benchmarking))
-    /// - Reserved addresses ([`is_reserved`](Ipv4Addr::is_reserved))
-    /// - The [broadcast address] ([`is_broadcast`](Ipv4Addr::is_broadcast))
-    ///
-    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv4 Special-Purpose Address Registry].
-    ///
-    /// [IANA IPv4 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
-    /// [unspecified address]: Ipv4Addr::UNSPECIFIED
-    /// [broadcast address]: Ipv4Addr::BROADCAST
-
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv4Addr;
-    ///
-    /// // Most IPv4 addresses are globally reachable:
-    /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
-    ///
-    /// // However some addresses have been assigned a special meaning
-    /// // that makes them not globally reachable. Some examples are:
-    ///
-    /// // The unspecified address (`0.0.0.0`)
-    /// assert_eq!(Ipv4Addr::UNSPECIFIED.is_global(), false);
-    ///
-    /// // Addresses reserved for private use (`10.0.0.0/8`, `172.16.0.0/12`, 192.168.0.0/16)
-    /// assert_eq!(Ipv4Addr::new(10, 254, 0, 0).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(192, 168, 10, 65).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_global(), false);
-    ///
-    /// // Addresses in the shared address space (`100.64.0.0/10`)
-    /// assert_eq!(Ipv4Addr::new(100, 100, 0, 0).is_global(), false);
-    ///
-    /// // The loopback addresses (`127.0.0.0/8`)
-    /// assert_eq!(Ipv4Addr::LOCALHOST.is_global(), false);
-    ///
-    /// // Link-local addresses (`169.254.0.0/16`)
-    /// assert_eq!(Ipv4Addr::new(169, 254, 45, 1).is_global(), false);
-    ///
-    /// // Addresses reserved for documentation (`192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24`)
-    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_global(), false);
-    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_global(), false);
-    ///
-    /// // Addresses reserved for benchmarking (`198.18.0.0/15`)
-    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_global(), false);
-    ///
-    /// // Reserved addresses (`240.0.0.0/4`)
-    /// assert_eq!(Ipv4Addr::new(250, 10, 20, 30).is_global(), false);
-    ///
-    /// // The broadcast address (`255.255.255.255`)
-    /// assert_eq!(Ipv4Addr::BROADCAST.is_global(), false);
-    ///
-    /// // For a complete overview see the IANA IPv4 Special-Purpose Address Registry.
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_global(&self) -> bool {
-        !(self.octets()[0] == 0 // "This network"
-            || self.is_private()
-            || self.is_shared()
-            || self.is_loopback()
-            || self.is_link_local()
-            // addresses reserved for future protocols (`192.0.0.0/24`)
-            ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
-            || self.is_documentation()
-            || self.is_benchmarking()
-            || self.is_reserved()
-            || self.is_broadcast())
-    }
-
-    /// Returns [`true`] if this address is part of the Shared Address Space defined in
-    /// [IETF RFC 6598] (`100.64.0.0/10`).
-    ///
-    /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(100, 64, 0, 0).is_shared(), true);
-    /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true);
-    /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_shared(&self) -> bool {
-        self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
-    }
-
-    /// Returns [`true`] if this address part of the `198.18.0.0/15` range, which is reserved for
-    /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0`
-    /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`.
-    ///
-    /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544
-    /// [errata 423]: https://www.rfc-editor.org/errata/eid423
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(198, 17, 255, 255).is_benchmarking(), false);
-    /// assert_eq!(Ipv4Addr::new(198, 18, 0, 0).is_benchmarking(), true);
-    /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true);
-    /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_benchmarking(&self) -> bool {
-        self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
-    }
-
-    /// Returns [`true`] if this address is reserved by IANA for future use. [IETF RFC 1112]
-    /// defines the block of reserved addresses as `240.0.0.0/4`. This range normally includes the
-    /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since
-    /// it is obviously not reserved for future use.
-    ///
-    /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112
-    ///
-    /// # Warning
-    ///
-    /// As IANA assigns new addresses, this method will be
-    /// updated. This may result in non-reserved addresses being
-    /// treated as reserved in code that relies on an outdated version
-    /// of this method.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(240, 0, 0, 0).is_reserved(), true);
-    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 254).is_reserved(), true);
-    ///
-    /// assert_eq!(Ipv4Addr::new(239, 255, 255, 255).is_reserved(), false);
-    /// // The broadcast address is not considered as reserved for future use by this implementation
-    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_reserved(&self) -> bool {
-        self.octets()[0] & 240 == 240 && !self.is_broadcast()
-    }
-
-    /// Returns [`true`] if this is a multicast address (`224.0.0.0/4`).
-    ///
-    /// Multicast addresses have a most significant octet between `224` and `239`,
-    /// and is defined by [IETF RFC 5771].
-    ///
-    /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(224, 254, 0, 0).is_multicast(), true);
-    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true);
-    /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_multicast(&self) -> bool {
-        self.octets()[0] >= 224 && self.octets()[0] <= 239
-    }
-
-    /// Returns [`true`] if this is a broadcast address (`255.255.255.255`).
-    ///
-    /// A broadcast address has all octets set to `255` as defined in [IETF RFC 919].
-    ///
-    /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true);
-    /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_broadcast(&self) -> bool {
-        u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets())
-    }
-
-    /// Returns [`true`] if this address is in a range designated for documentation.
-    ///
-    /// This is defined in [IETF RFC 5737]:
-    ///
-    /// - `192.0.2.0/24` (TEST-NET-1)
-    /// - `198.51.100.0/24` (TEST-NET-2)
-    /// - `203.0.113.0/24` (TEST-NET-3)
-    ///
-    /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).is_documentation(), true);
-    /// assert_eq!(Ipv4Addr::new(198, 51, 100, 65).is_documentation(), true);
-    /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true);
-    /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_documentation(&self) -> bool {
-        matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
-    }
-
-    /// Converts this address to an [IPv4-compatible] [`IPv6` address].
-    ///
-    /// `a.b.c.d` becomes `::a.b.c.d`
-    ///
-    /// Note that IPv4-compatible addresses have been officially deprecated.
-    /// If you don't explicitly need an IPv4-compatible address for legacy reasons, consider using `to_ipv6_mapped` instead.
-    ///
-    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
-    /// [`IPv6` address]: Ipv6Addr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(
-    ///     Ipv4Addr::new(192, 0, 2, 255).to_ipv6_compatible(),
-    ///     Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x2ff)
-    /// );
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_ipv6_compatible(&self) -> Ipv6Addr {
-        let [a, b, c, d] = self.octets();
-        Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] }
-    }
-
-    /// Converts this address to an [IPv4-mapped] [`IPv6` address].
-    ///
-    /// `a.b.c.d` becomes `::ffff:a.b.c.d`
-    ///
-    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
-    /// [`IPv6` address]: Ipv6Addr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(),
-    ///            Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x2ff));
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_ipv6_mapped(&self) -> Ipv6Addr {
-        let [a, b, c, d] = self.octets();
-        Ipv6Addr { octets: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }
-    }
-}
-
-#[stable(feature = "ip_addr", since = "1.7.0")]
-impl fmt::Display for IpAddr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            IpAddr::V4(ip) => ip.fmt(fmt),
-            IpAddr::V6(ip) => ip.fmt(fmt),
-        }
-    }
-}
-
-#[stable(feature = "ip_addr", since = "1.7.0")]
-impl fmt::Debug for IpAddr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<Ipv4Addr> for IpAddr {
-    /// Copies this address to a new `IpAddr::V4`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr};
-    ///
-    /// let addr = Ipv4Addr::new(127, 0, 0, 1);
-    ///
-    /// assert_eq!(
-    ///     IpAddr::V4(addr),
-    ///     IpAddr::from(addr)
-    /// )
-    /// ```
-    #[inline]
-    fn from(ipv4: Ipv4Addr) -> IpAddr {
-        IpAddr::V4(ipv4)
-    }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<Ipv6Addr> for IpAddr {
-    /// Copies this address to a new `IpAddr::V6`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv6Addr};
-    ///
-    /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
-    ///
-    /// assert_eq!(
-    ///     IpAddr::V6(addr),
-    ///     IpAddr::from(addr)
-    /// );
-    /// ```
-    #[inline]
-    fn from(ipv6: Ipv6Addr) -> IpAddr {
-        IpAddr::V6(ipv6)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for Ipv4Addr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let octets = self.octets();
-
-        // If there are no alignment requirements, write the IP address directly to `f`.
-        // Otherwise, write it to a local buffer and then use `f.pad`.
-        if fmt.precision().is_none() && fmt.width().is_none() {
-            write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
-        } else {
-            const LONGEST_IPV4_ADDR: &str = "255.255.255.255";
-
-            let mut buf = DisplayBuffer::<{ LONGEST_IPV4_ADDR.len() }>::new();
-            // Buffer is long enough for the longest possible IPv4 address, so this should never fail.
-            write!(buf, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3]).unwrap();
-
-            fmt.pad(buf.as_str())
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Ipv4Addr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<Ipv4Addr> for IpAddr {
-    #[inline]
-    fn eq(&self, other: &Ipv4Addr) -> bool {
-        match self {
-            IpAddr::V4(v4) => v4 == other,
-            IpAddr::V6(_) => false,
-        }
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<IpAddr> for Ipv4Addr {
-    #[inline]
-    fn eq(&self, other: &IpAddr) -> bool {
-        match other {
-            IpAddr::V4(v4) => self == v4,
-            IpAddr::V6(_) => false,
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for Ipv4Addr {
-    #[inline]
-    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<Ipv4Addr> for IpAddr {
-    #[inline]
-    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
-        match self {
-            IpAddr::V4(v4) => v4.partial_cmp(other),
-            IpAddr::V6(_) => Some(Ordering::Greater),
-        }
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<IpAddr> for Ipv4Addr {
-    #[inline]
-    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
-        match other {
-            IpAddr::V4(v4) => self.partial_cmp(v4),
-            IpAddr::V6(_) => Some(Ordering::Less),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for Ipv4Addr {
-    #[inline]
-    fn cmp(&self, other: &Ipv4Addr) -> Ordering {
-        self.octets.cmp(&other.octets)
-    }
-}
+pub use core::net::Ipv6MulticastScope;
 
 impl IntoInner<c::in_addr> for Ipv4Addr {
     #[inline]
     fn into_inner(self) -> c::in_addr {
         // `s_addr` is stored as BE on all machines and the array is in BE order.
         // So the native endian conversion method is used so that it's never swapped.
-        c::in_addr { s_addr: u32::from_ne_bytes(self.octets) }
+        c::in_addr { s_addr: u32::from_ne_bytes(self.octets()) }
     }
 }
 impl FromInner<c::in_addr> for Ipv4Addr {
     fn from_inner(addr: c::in_addr) -> Ipv4Addr {
-        Ipv4Addr { octets: addr.s_addr.to_ne_bytes() }
-    }
-}
-
-#[stable(feature = "ip_u32", since = "1.1.0")]
-impl From<Ipv4Addr> for u32 {
-    /// Converts an `Ipv4Addr` into a host byte order `u32`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::new(0x12, 0x34, 0x56, 0x78);
-    /// assert_eq!(0x12345678, u32::from(addr));
-    /// ```
-    #[inline]
-    fn from(ip: Ipv4Addr) -> u32 {
-        u32::from_be_bytes(ip.octets)
-    }
-}
-
-#[stable(feature = "ip_u32", since = "1.1.0")]
-impl From<u32> for Ipv4Addr {
-    /// Converts a host byte order `u32` into an `Ipv4Addr`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::from(0x12345678);
-    /// assert_eq!(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78), addr);
-    /// ```
-    #[inline]
-    fn from(ip: u32) -> Ipv4Addr {
-        Ipv4Addr { octets: ip.to_be_bytes() }
-    }
-}
-
-#[stable(feature = "from_slice_v4", since = "1.9.0")]
-impl From<[u8; 4]> for Ipv4Addr {
-    /// Creates an `Ipv4Addr` from a four element byte array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv4Addr;
-    ///
-    /// let addr = Ipv4Addr::from([13u8, 12u8, 11u8, 10u8]);
-    /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
-    /// ```
-    #[inline]
-    fn from(octets: [u8; 4]) -> Ipv4Addr {
-        Ipv4Addr { octets }
-    }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u8; 4]> for IpAddr {
-    /// Creates an `IpAddr::V4` from a four element byte array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr};
-    ///
-    /// let addr = IpAddr::from([13u8, 12u8, 11u8, 10u8]);
-    /// assert_eq!(IpAddr::V4(Ipv4Addr::new(13, 12, 11, 10)), addr);
-    /// ```
-    #[inline]
-    fn from(octets: [u8; 4]) -> IpAddr {
-        IpAddr::V4(Ipv4Addr::from(octets))
-    }
-}
-
-impl Ipv6Addr {
-    /// Creates a new IPv6 address from eight 16-bit segments.
-    ///
-    /// The result will represent the IP address `a:b:c:d:e:f:g:h`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[inline]
-    pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
-        let addr16 = [
-            a.to_be(),
-            b.to_be(),
-            c.to_be(),
-            d.to_be(),
-            e.to_be(),
-            f.to_be(),
-            g.to_be(),
-            h.to_be(),
-        ];
-        Ipv6Addr {
-            // All elements in `addr16` are big endian.
-            // SAFETY: `[u16; 8]` is always safe to transmute to `[u8; 16]`.
-            octets: unsafe { transmute::<_, [u8; 16]>(addr16) },
-        }
-    }
-
-    /// An IPv6 address representing localhost: `::1`.
-    ///
-    /// This corresponds to constant `IN6ADDR_LOOPBACK_INIT` or `in6addr_loopback` in other
-    /// languages.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::LOCALHOST;
-    /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    /// ```
-    #[doc(alias = "IN6ADDR_LOOPBACK_INIT")]
-    #[doc(alias = "in6addr_loopback")]
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const LOCALHOST: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
-
-    /// An IPv6 address representing the unspecified address: `::`
-    ///
-    /// This corresponds to constant `IN6ADDR_ANY_INIT` or `in6addr_any` in other languages.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::UNSPECIFIED;
-    /// assert_eq!(addr, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
-    /// ```
-    #[doc(alias = "IN6ADDR_ANY_INIT")]
-    #[doc(alias = "in6addr_any")]
-    #[stable(feature = "ip_constructors", since = "1.30.0")]
-    pub const UNSPECIFIED: Self = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
-
-    /// Returns the eight 16-bit segments that make up this address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(),
-    ///            [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[inline]
-    pub const fn segments(&self) -> [u16; 8] {
-        // All elements in `self.octets` must be big endian.
-        // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`.
-        let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.octets) };
-        // We want native endian u16
-        [
-            u16::from_be(a),
-            u16::from_be(b),
-            u16::from_be(c),
-            u16::from_be(d),
-            u16::from_be(e),
-            u16::from_be(f),
-            u16::from_be(g),
-            u16::from_be(h),
-        ]
-    }
-
-    /// Returns [`true`] for the special 'unspecified' address (`::`).
-    ///
-    /// This property is defined in [IETF RFC 4291].
-    ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unspecified(&self) -> bool {
-        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets())
-    }
-
-    /// Returns [`true`] if this is the [loopback address] (`::1`),
-    /// as defined in [IETF RFC 4291 section 2.5.3].
-    ///
-    /// Contrary to IPv4, in IPv6 there is only one loopback address.
-    ///
-    /// [loopback address]: Ipv6Addr::LOCALHOST
-    /// [IETF RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_loopback(&self) -> bool {
-        u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets())
-    }
-
-    /// Returns [`true`] if the address appears to be globally reachable
-    /// as specified by the [IANA IPv6 Special-Purpose Address Registry].
-    /// Whether or not an address is practically reachable will depend on your network configuration.
-    ///
-    /// Most IPv6 addresses are globally reachable;
-    /// unless they are specifically defined as *not* globally reachable.
-    ///
-    /// Non-exhaustive list of notable addresses that are not globally reachable:
-    /// - The [unspecified address] ([`is_unspecified`](Ipv6Addr::is_unspecified))
-    /// - The [loopback address] ([`is_loopback`](Ipv6Addr::is_loopback))
-    /// - IPv4-mapped addresses
-    /// - Addresses reserved for benchmarking
-    /// - Addresses reserved for documentation ([`is_documentation`](Ipv6Addr::is_documentation))
-    /// - Unique local addresses ([`is_unique_local`](Ipv6Addr::is_unique_local))
-    /// - Unicast addresses with link-local scope ([`is_unicast_link_local`](Ipv6Addr::is_unicast_link_local))
-    ///
-    /// For the complete overview of which addresses are globally reachable, see the table at the [IANA IPv6 Special-Purpose Address Registry].
-    ///
-    /// Note that an address having global scope is not the same as being globally reachable,
-    /// and there is no direct relation between the two concepts: There exist addresses with global scope
-    /// that are not globally reachable (for example unique local addresses),
-    /// and addresses that are globally reachable without having global scope
-    /// (multicast addresses with non-global scope).
-    ///
-    /// [IANA IPv6 Special-Purpose Address Registry]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
-    /// [unspecified address]: Ipv6Addr::UNSPECIFIED
-    /// [loopback address]: Ipv6Addr::LOCALHOST
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// // Most IPv6 addresses are globally reachable:
-    /// assert_eq!(Ipv6Addr::new(0x26, 0, 0x1c9, 0, 0, 0xafc8, 0x10, 0x1).is_global(), true);
-    ///
-    /// // However some addresses have been assigned a special meaning
-    /// // that makes them not globally reachable. Some examples are:
-    ///
-    /// // The unspecified address (`::`)
-    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_global(), false);
-    ///
-    /// // The loopback address (`::1`)
-    /// assert_eq!(Ipv6Addr::LOCALHOST.is_global(), false);
-    ///
-    /// // IPv4-mapped addresses (`::ffff:0:0/96`)
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_global(), false);
-    ///
-    /// // Addresses reserved for benchmarking (`2001:2::/48`)
-    /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false);
-    ///
-    /// // Addresses reserved for documentation (`2001:db8::/32`)
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false);
-    ///
-    /// // Unique local addresses (`fc00::/7`)
-    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
-    ///
-    /// // Unicast addresses with link-local scope (`fe80::/10`)
-    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 1).is_global(), false);
-    ///
-    /// // For a complete overview see the IANA IPv6 Special-Purpose Address Registry.
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_global(&self) -> bool {
-        !(self.is_unspecified()
-            || self.is_loopback()
-            // IPv4-mapped Address (`::ffff:0:0/96`)
-            || matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
-            // IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
-            || matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
-            // Discard-Only Address Block (`100::/64`)
-            || matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
-            // IETF Protocol Assignments (`2001::/23`)
-            || (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
-                && !(
-                    // Port Control Protocol Anycast (`2001:1::1`)
-                    u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
-                    // Traversal Using Relays around NAT Anycast (`2001:1::2`)
-                    || u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
-                    // AMT (`2001:3::/32`)
-                    || matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
-                    // AS112-v6 (`2001:4:112::/48`)
-                    || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
-                    // ORCHIDv2 (`2001:20::/28`)
-                    || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
-                ))
-            || self.is_documentation()
-            || self.is_unique_local()
-            || self.is_unicast_link_local())
-    }
-
-    /// Returns [`true`] if this is a unique local address (`fc00::/7`).
-    ///
-    /// This property is defined in [IETF RFC 4193].
-    ///
-    /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false);
-    /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unique_local(&self) -> bool {
-        (self.segments()[0] & 0xfe00) == 0xfc00
-    }
-
-    /// Returns [`true`] if this is a unicast address, as defined by [IETF RFC 4291].
-    /// Any address that is not a [multicast address] (`ff00::/8`) is unicast.
-    ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-    /// [multicast address]: Ipv6Addr::is_multicast
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// // The unspecified and loopback addresses are unicast.
-    /// assert_eq!(Ipv6Addr::UNSPECIFIED.is_unicast(), true);
-    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast(), true);
-    ///
-    /// // Any address that is not a multicast address (`ff00::/8`) is unicast.
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast(), true);
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_unicast(), false);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unicast(&self) -> bool {
-        !self.is_multicast()
-    }
-
-    /// Returns `true` if the address is a unicast address with link-local scope,
-    /// as defined in [RFC 4291].
-    ///
-    /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
-    /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
-    /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
-    ///
-    /// ```text
-    /// | 10 bits  |         54 bits         |          64 bits           |
-    /// +----------+-------------------------+----------------------------+
-    /// |1111111010|           0             |       interface ID         |
-    /// +----------+-------------------------+----------------------------+
-    /// ```
-    /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
-    /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
-    /// and those addresses will have link-local scope.
-    ///
-    /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
-    /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
-    ///
-    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
-    /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
-    /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
-    /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
-    /// [loopback address]: Ipv6Addr::LOCALHOST
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// // The loopback address (`::1`) does not actually have link-local scope.
-    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
-    ///
-    /// // Only addresses in `fe80::/10` have link-local scope.
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
-    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
-    ///
-    /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
-    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
-    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unicast_link_local(&self) -> bool {
-        (self.segments()[0] & 0xffc0) == 0xfe80
-    }
-
-    /// Returns [`true`] if this is an address reserved for documentation
-    /// (`2001:db8::/32`).
-    ///
-    /// This property is defined in [IETF RFC 3849].
-    ///
-    /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false);
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_documentation(&self) -> bool {
-        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
-    }
-
-    /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`).
-    ///
-    /// This property is defined in [IETF RFC 5180], where it is mistakenly specified as covering the range `2001:0200::/48`.
-    /// This is corrected in [IETF RFC Errata 1752] to `2001:0002::/48`.
-    ///
-    /// [IETF RFC 5180]: https://tools.ietf.org/html/rfc5180
-    /// [IETF RFC Errata 1752]: https://www.rfc-editor.org/errata_search.php?eid=1752
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc613, 0x0).is_benchmarking(), false);
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0x2, 0, 0, 0, 0, 0, 0).is_benchmarking(), true);
-    /// ```
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_benchmarking(&self) -> bool {
-        (self.segments()[0] == 0x2001) && (self.segments()[1] == 0x2) && (self.segments()[2] == 0)
-    }
-
-    /// Returns [`true`] if the address is a globally routable unicast address.
-    ///
-    /// The following return false:
-    ///
-    /// - the loopback address
-    /// - the link-local addresses
-    /// - unique local addresses
-    /// - the unspecified address
-    /// - the address range reserved for documentation
-    ///
-    /// This method returns [`true`] for site-local addresses as per [RFC 4291 section 2.5.7]
-    ///
-    /// ```no_rust
-    /// The special behavior of [the site-local unicast] prefix defined in [RFC3513] must no longer
-    /// be supported in new implementations (i.e., new implementations must treat this prefix as
-    /// Global Unicast).
-    /// ```
-    ///
-    /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn is_unicast_global(&self) -> bool {
-        self.is_unicast()
-            && !self.is_loopback()
-            && !self.is_unicast_link_local()
-            && !self.is_unique_local()
-            && !self.is_unspecified()
-            && !self.is_documentation()
-            && !self.is_benchmarking()
-    }
-
-    /// Returns the address's multicast scope if the address is multicast.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::{Ipv6Addr, Ipv6MulticastScope};
-    ///
-    /// assert_eq!(
-    ///     Ipv6Addr::new(0xff0e, 0, 0, 0, 0, 0, 0, 0).multicast_scope(),
-    ///     Some(Ipv6MulticastScope::Global)
-    /// );
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use]
-    #[inline]
-    pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
-        if self.is_multicast() {
-            match self.segments()[0] & 0x000f {
-                1 => Some(Ipv6MulticastScope::InterfaceLocal),
-                2 => Some(Ipv6MulticastScope::LinkLocal),
-                3 => Some(Ipv6MulticastScope::RealmLocal),
-                4 => Some(Ipv6MulticastScope::AdminLocal),
-                5 => Some(Ipv6MulticastScope::SiteLocal),
-                8 => Some(Ipv6MulticastScope::OrganizationLocal),
-                14 => Some(Ipv6MulticastScope::Global),
-                _ => None,
-            }
-        } else {
-            None
-        }
-    }
-
-    /// Returns [`true`] if this is a multicast address (`ff00::/8`).
-    ///
-    /// This property is defined by [IETF RFC 4291].
-    ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(since = "1.7.0", feature = "ip_17")]
-    #[must_use]
-    #[inline]
-    pub const fn is_multicast(&self) -> bool {
-        (self.segments()[0] & 0xff00) == 0xff00
-    }
-
-    /// Converts this address to an [`IPv4` address] if it's an [IPv4-mapped] address,
-    /// as defined in [IETF RFC 4291 section 2.5.5.2], otherwise returns [`None`].
-    ///
-    /// `::ffff:a.b.c.d` becomes `a.b.c.d`.
-    /// All addresses *not* starting with `::ffff` will return `None`.
-    ///
-    /// [`IPv4` address]: Ipv4Addr
-    /// [IPv4-mapped]: Ipv6Addr
-    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4_mapped(), None);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4_mapped(),
-    ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[stable(feature = "ipv6_to_ipv4_mapped", since = "1.63.0")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
-        match self.octets() {
-            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => {
-                Some(Ipv4Addr::new(a, b, c, d))
-            }
-            _ => None,
-        }
-    }
-
-    /// Converts this address to an [`IPv4` address] if it is either
-    /// an [IPv4-compatible] address as defined in [IETF RFC 4291 section 2.5.5.1],
-    /// or an [IPv4-mapped] address as defined in [IETF RFC 4291 section 2.5.5.2],
-    /// otherwise returns [`None`].
-    ///
-    /// Note that this will return an [`IPv4` address] for the IPv6 loopback address `::1`. Use
-    /// [`Ipv6Addr::to_ipv4_mapped`] to avoid this.
-    ///
-    /// `::a.b.c.d` and `::ffff:a.b.c.d` become `a.b.c.d`. `::1` becomes `0.0.0.1`.
-    /// All addresses *not* starting with either all zeroes or `::ffff` will return `None`.
-    ///
-    /// [`IPv4` address]: Ipv4Addr
-    /// [IPv4-compatible]: Ipv6Addr#ipv4-compatible-ipv6-addresses
-    /// [IPv4-mapped]: Ipv6Addr#ipv4-mapped-ipv6-addresses
-    /// [IETF RFC 4291 section 2.5.5.1]: https://tools.ietf.org/html/rfc4291#section-2.5.5.1
-    /// [IETF RFC 4291 section 2.5.5.2]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{Ipv4Addr, Ipv6Addr};
-    ///
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).to_ipv4(), None);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).to_ipv4(),
-    ///            Some(Ipv4Addr::new(192, 10, 2, 255)));
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(),
-    ///            Some(Ipv4Addr::new(0, 0, 0, 1)));
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_50", since = "1.50.0")]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_ipv4(&self) -> Option<Ipv4Addr> {
-        if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() {
-            let [a, b] = ab.to_be_bytes();
-            let [c, d] = cd.to_be_bytes();
-            Some(Ipv4Addr::new(a, b, c, d))
-        } else {
-            None
-        }
-    }
-
-    /// Converts this address to an `IpAddr::V4` if it is an IPv4-mapped addresses, otherwise it
-    /// returns self wrapped in an `IpAddr::V6`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).is_loopback(), false);
-    /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x7f00, 0x1).to_canonical().is_loopback(), true);
-    /// ```
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[unstable(feature = "ip", issue = "27709")]
-    #[must_use = "this returns the result of the operation, \
-                  without modifying the original"]
-    #[inline]
-    pub const fn to_canonical(&self) -> IpAddr {
-        if let Some(mapped) = self.to_ipv4_mapped() {
-            return IpAddr::V4(mapped);
-        }
-        IpAddr::V6(*self)
-    }
-
-    /// Returns the sixteen eight-bit integers the IPv6 address consists of.
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).octets(),
-    ///            [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
-    /// ```
-    #[rustc_const_stable(feature = "const_ip_32", since = "1.32.0")]
-    #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
-    #[must_use]
-    #[inline]
-    pub const fn octets(&self) -> [u8; 16] {
-        self.octets
-    }
-}
-
-/// Write an Ipv6Addr, conforming to the canonical style described by
-/// [RFC 5952](https://tools.ietf.org/html/rfc5952).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for Ipv6Addr {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // If there are no alignment requirements, write the IP address directly to `f`.
-        // Otherwise, write it to a local buffer and then use `f.pad`.
-        if f.precision().is_none() && f.width().is_none() {
-            let segments = self.segments();
-
-            // Special case for :: and ::1; otherwise they get written with the
-            // IPv4 formatter
-            if self.is_unspecified() {
-                f.write_str("::")
-            } else if self.is_loopback() {
-                f.write_str("::1")
-            } else if let Some(ipv4) = self.to_ipv4() {
-                match segments[5] {
-                    // IPv4 Compatible address
-                    0 => write!(f, "::{}", ipv4),
-                    // IPv4 Mapped address
-                    0xffff => write!(f, "::ffff:{}", ipv4),
-                    _ => unreachable!(),
-                }
-            } else {
-                #[derive(Copy, Clone, Default)]
-                struct Span {
-                    start: usize,
-                    len: usize,
-                }
-
-                // Find the inner 0 span
-                let zeroes = {
-                    let mut longest = Span::default();
-                    let mut current = Span::default();
-
-                    for (i, &segment) in segments.iter().enumerate() {
-                        if segment == 0 {
-                            if current.len == 0 {
-                                current.start = i;
-                            }
-
-                            current.len += 1;
-
-                            if current.len > longest.len {
-                                longest = current;
-                            }
-                        } else {
-                            current = Span::default();
-                        }
-                    }
-
-                    longest
-                };
-
-                /// Write a colon-separated part of the address
-                #[inline]
-                fn fmt_subslice(f: &mut fmt::Formatter<'_>, chunk: &[u16]) -> fmt::Result {
-                    if let Some((first, tail)) = chunk.split_first() {
-                        write!(f, "{:x}", first)?;
-                        for segment in tail {
-                            f.write_char(':')?;
-                            write!(f, "{:x}", segment)?;
-                        }
-                    }
-                    Ok(())
-                }
-
-                if zeroes.len > 1 {
-                    fmt_subslice(f, &segments[..zeroes.start])?;
-                    f.write_str("::")?;
-                    fmt_subslice(f, &segments[zeroes.start + zeroes.len..])
-                } else {
-                    fmt_subslice(f, &segments)
-                }
-            }
-        } else {
-            const LONGEST_IPV6_ADDR: &str = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
-
-            let mut buf = DisplayBuffer::<{ LONGEST_IPV6_ADDR.len() }>::new();
-            // Buffer is long enough for the longest possible IPv6 address, so this should never fail.
-            write!(buf, "{}", self).unwrap();
-
-            f.pad(buf.as_str())
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Ipv6Addr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<IpAddr> for Ipv6Addr {
-    #[inline]
-    fn eq(&self, other: &IpAddr) -> bool {
-        match other {
-            IpAddr::V4(_) => false,
-            IpAddr::V6(v6) => self == v6,
-        }
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialEq<Ipv6Addr> for IpAddr {
-    #[inline]
-    fn eq(&self, other: &Ipv6Addr) -> bool {
-        match self {
-            IpAddr::V4(_) => false,
-            IpAddr::V6(v6) => v6 == other,
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl PartialOrd for Ipv6Addr {
-    #[inline]
-    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<Ipv6Addr> for IpAddr {
-    #[inline]
-    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
-        match self {
-            IpAddr::V4(_) => Some(Ordering::Less),
-            IpAddr::V6(v6) => v6.partial_cmp(other),
-        }
-    }
-}
-
-#[stable(feature = "ip_cmp", since = "1.16.0")]
-impl PartialOrd<IpAddr> for Ipv6Addr {
-    #[inline]
-    fn partial_cmp(&self, other: &IpAddr) -> Option<Ordering> {
-        match other {
-            IpAddr::V4(_) => Some(Ordering::Greater),
-            IpAddr::V6(v6) => self.partial_cmp(v6),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Ord for Ipv6Addr {
-    #[inline]
-    fn cmp(&self, other: &Ipv6Addr) -> Ordering {
-        self.segments().cmp(&other.segments())
+        Ipv4Addr::from(addr.s_addr.to_ne_bytes())
     }
 }
 
 impl IntoInner<c::in6_addr> for Ipv6Addr {
     fn into_inner(self) -> c::in6_addr {
-        c::in6_addr { s6_addr: self.octets }
+        c::in6_addr { s6_addr: self.octets() }
     }
 }
 impl FromInner<c::in6_addr> for Ipv6Addr {
     #[inline]
     fn from_inner(addr: c::in6_addr) -> Ipv6Addr {
-        Ipv6Addr { octets: addr.s6_addr }
-    }
-}
-
-#[stable(feature = "i128", since = "1.26.0")]
-impl From<Ipv6Addr> for u128 {
-    /// Convert an `Ipv6Addr` into a host byte order `u128`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::new(
-    ///     0x1020, 0x3040, 0x5060, 0x7080,
-    ///     0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
-    /// );
-    /// assert_eq!(0x102030405060708090A0B0C0D0E0F00D_u128, u128::from(addr));
-    /// ```
-    #[inline]
-    fn from(ip: Ipv6Addr) -> u128 {
-        u128::from_be_bytes(ip.octets)
-    }
-}
-#[stable(feature = "i128", since = "1.26.0")]
-impl From<u128> for Ipv6Addr {
-    /// Convert a host byte order `u128` into an `Ipv6Addr`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::from(0x102030405060708090A0B0C0D0E0F00D_u128);
-    /// assert_eq!(
-    ///     Ipv6Addr::new(
-    ///         0x1020, 0x3040, 0x5060, 0x7080,
-    ///         0x90A0, 0xB0C0, 0xD0E0, 0xF00D,
-    ///     ),
-    ///     addr);
-    /// ```
-    #[inline]
-    fn from(ip: u128) -> Ipv6Addr {
-        Ipv6Addr::from(ip.to_be_bytes())
-    }
-}
-
-#[stable(feature = "ipv6_from_octets", since = "1.9.0")]
-impl From<[u8; 16]> for Ipv6Addr {
-    /// Creates an `Ipv6Addr` from a sixteen element byte array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::from([
-    ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
-    ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
-    /// ]);
-    /// assert_eq!(
-    ///     Ipv6Addr::new(
-    ///         0x1918, 0x1716,
-    ///         0x1514, 0x1312,
-    ///         0x1110, 0x0f0e,
-    ///         0x0d0c, 0x0b0a
-    ///     ),
-    ///     addr
-    /// );
-    /// ```
-    #[inline]
-    fn from(octets: [u8; 16]) -> Ipv6Addr {
-        Ipv6Addr { octets }
-    }
-}
-
-#[stable(feature = "ipv6_from_segments", since = "1.16.0")]
-impl From<[u16; 8]> for Ipv6Addr {
-    /// Creates an `Ipv6Addr` from an eight element 16-bit array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let addr = Ipv6Addr::from([
-    ///     525u16, 524u16, 523u16, 522u16,
-    ///     521u16, 520u16, 519u16, 518u16,
-    /// ]);
-    /// assert_eq!(
-    ///     Ipv6Addr::new(
-    ///         0x20d, 0x20c,
-    ///         0x20b, 0x20a,
-    ///         0x209, 0x208,
-    ///         0x207, 0x206
-    ///     ),
-    ///     addr
-    /// );
-    /// ```
-    #[inline]
-    fn from(segments: [u16; 8]) -> Ipv6Addr {
-        let [a, b, c, d, e, f, g, h] = segments;
-        Ipv6Addr::new(a, b, c, d, e, f, g, h)
-    }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u8; 16]> for IpAddr {
-    /// Creates an `IpAddr::V6` from a sixteen element byte array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv6Addr};
-    ///
-    /// let addr = IpAddr::from([
-    ///     25u8, 24u8, 23u8, 22u8, 21u8, 20u8, 19u8, 18u8,
-    ///     17u8, 16u8, 15u8, 14u8, 13u8, 12u8, 11u8, 10u8,
-    /// ]);
-    /// assert_eq!(
-    ///     IpAddr::V6(Ipv6Addr::new(
-    ///         0x1918, 0x1716,
-    ///         0x1514, 0x1312,
-    ///         0x1110, 0x0f0e,
-    ///         0x0d0c, 0x0b0a
-    ///     )),
-    ///     addr
-    /// );
-    /// ```
-    #[inline]
-    fn from(octets: [u8; 16]) -> IpAddr {
-        IpAddr::V6(Ipv6Addr::from(octets))
-    }
-}
-
-#[stable(feature = "ip_from_slice", since = "1.17.0")]
-impl From<[u16; 8]> for IpAddr {
-    /// Creates an `IpAddr::V6` from an eight element 16-bit array.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv6Addr};
-    ///
-    /// let addr = IpAddr::from([
-    ///     525u16, 524u16, 523u16, 522u16,
-    ///     521u16, 520u16, 519u16, 518u16,
-    /// ]);
-    /// assert_eq!(
-    ///     IpAddr::V6(Ipv6Addr::new(
-    ///         0x20d, 0x20c,
-    ///         0x20b, 0x20a,
-    ///         0x209, 0x208,
-    ///         0x207, 0x206
-    ///     )),
-    ///     addr
-    /// );
-    /// ```
-    #[inline]
-    fn from(segments: [u16; 8]) -> IpAddr {
-        IpAddr::V6(Ipv6Addr::from(segments))
+        Ipv6Addr::from(addr.s6_addr)
     }
 }
diff --git a/library/std/src/net/ip_addr/tests.rs b/library/std/src/net/ip_addr/tests.rs
index 0eb59d45de7..ab99c0c2fcc 100644
--- a/library/std/src/net/ip_addr/tests.rs
+++ b/library/std/src/net/ip_addr/tests.rs
@@ -1,1039 +1,8 @@
-use crate::net::test::{sa4, sa6, tsa};
-use crate::net::*;
-use crate::str::FromStr;
-
-#[test]
-fn test_from_str_ipv4() {
-    assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
-    assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
-    assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
-
-    // out of range
-    let none: Option<Ipv4Addr> = "256.0.0.1".parse().ok();
-    assert_eq!(None, none);
-    // too short
-    let none: Option<Ipv4Addr> = "255.0.0".parse().ok();
-    assert_eq!(None, none);
-    // too long
-    let none: Option<Ipv4Addr> = "255.0.0.1.2".parse().ok();
-    assert_eq!(None, none);
-    // no number between dots
-    let none: Option<Ipv4Addr> = "255.0..1".parse().ok();
-    assert_eq!(None, none);
-    // octal
-    let none: Option<Ipv4Addr> = "255.0.0.01".parse().ok();
-    assert_eq!(None, none);
-    // octal zero
-    let none: Option<Ipv4Addr> = "255.0.0.00".parse().ok();
-    assert_eq!(None, none);
-    let none: Option<Ipv4Addr> = "255.0.00.0".parse().ok();
-    assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_ipv6() {
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
-
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
-
-    assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse());
-
-    // too long group
-    let none: Option<Ipv6Addr> = "::00000".parse().ok();
-    assert_eq!(None, none);
-    // too short
-    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7".parse().ok();
-    assert_eq!(None, none);
-    // too long
-    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:8:9".parse().ok();
-    assert_eq!(None, none);
-    // triple colon
-    let none: Option<Ipv6Addr> = "1:2:::6:7:8".parse().ok();
-    assert_eq!(None, none);
-    // two double colons
-    let none: Option<Ipv6Addr> = "1:2::6::8".parse().ok();
-    assert_eq!(None, none);
-    // `::` indicating zero groups of zeros
-    let none: Option<Ipv6Addr> = "1:2:3:4::5:6:7:8".parse().ok();
-    assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_ipv4_in_ipv6() {
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse());
-    assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse());
-    assert_eq!(
-        Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
-        "64:ff9b::192.0.2.33".parse()
-    );
-    assert_eq!(
-        Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
-        "2001:db8:122:c000:2:2100:192.0.2.33".parse()
-    );
-
-    // colon after v4
-    let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
-    assert_eq!(None, none);
-    // not enough groups
-    let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
-    assert_eq!(None, none);
-    // too many groups
-    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
-    assert_eq!(None, none);
-}
-
-#[test]
-fn test_from_str_socket_addr() {
-    assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
-    assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse());
-    assert_eq!(
-        Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
-        "[2a02:6b8:0:1::1]:53".parse()
-    );
-    assert_eq!(
-        Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)),
-        "[2a02:6b8:0:1::1]:53".parse()
-    );
-    assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse());
-    assert_eq!(
-        Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)),
-        "[::127.0.0.1]:22".parse()
-    );
-
-    // without port
-    let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
-    assert_eq!(None, none);
-    // without port
-    let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
-    assert_eq!(None, none);
-    // wrong brackets around v4
-    let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
-    assert_eq!(None, none);
-    // port out of range
-    let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
-    assert_eq!(None, none);
-}
-
-#[test]
-fn ipv4_addr_to_string() {
-    assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1");
-    // Short address
-    assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1");
-    // Long address
-    assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127");
-
-    // Test padding
-    assert_eq!(format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1         ");
-    assert_eq!(format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), "         1.1.1.1");
-}
-
-#[test]
-fn ipv6_addr_to_string() {
-    // ipv4-mapped address
-    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
-    assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
-
-    // ipv4-compatible address
-    let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
-    assert_eq!(a1.to_string(), "::192.0.2.128");
-
-    // v6 address with no zero segments
-    assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f");
-
-    // longest possible IPv6 length
-    assert_eq!(
-        Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(),
-        "1111:2222:3333:4444:5555:6666:7777:8888"
-    );
-    // padding
-    assert_eq!(format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8     ");
-    assert_eq!(format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "     1:2:3:4:5:6:7:8");
-
-    // reduce a single run of zeros
-    assert_eq!(
-        "ae::ffff:102:304",
-        Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string()
-    );
-
-    // don't reduce just a single zero segment
-    assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
-
-    // 'any' address
-    assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
-
-    // loopback address
-    assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
-
-    // ends in zeros
-    assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
-
-    // two runs of zeros, second one is longer
-    assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
-
-    // two runs of zeros, equal length
-    assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
-
-    // don't prefix `0x` to each segment in `dbg!`.
-    assert_eq!("1::4:5:0:0:8", &format!("{:#?}", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8)));
-}
-
-#[test]
-fn ipv4_to_ipv6() {
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
-        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped()
-    );
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
-        Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible()
-    );
-}
-
-#[test]
-fn ipv6_to_ipv4_mapped() {
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(),
-        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
-    );
-    assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None);
-}
-
-#[test]
-fn ipv6_to_ipv4() {
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
-        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
-    );
-    assert_eq!(
-        Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
-        Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78))
-    );
-    assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None);
-}
-
-#[test]
-fn ip_properties() {
-    macro_rules! ip {
-        ($s:expr) => {
-            IpAddr::from_str($s).unwrap()
-        };
-    }
-
-    macro_rules! check {
-        ($s:expr) => {
-            check!($s, 0);
-        };
-
-        ($s:expr, $mask:expr) => {{
-            let unspec: u8 = 1 << 0;
-            let loopback: u8 = 1 << 1;
-            let global: u8 = 1 << 2;
-            let multicast: u8 = 1 << 3;
-            let doc: u8 = 1 << 4;
-            let benchmarking: u8 = 1 << 5;
-
-            if ($mask & unspec) == unspec {
-                assert!(ip!($s).is_unspecified());
-            } else {
-                assert!(!ip!($s).is_unspecified());
-            }
-
-            if ($mask & loopback) == loopback {
-                assert!(ip!($s).is_loopback());
-            } else {
-                assert!(!ip!($s).is_loopback());
-            }
-
-            if ($mask & global) == global {
-                assert!(ip!($s).is_global());
-            } else {
-                assert!(!ip!($s).is_global());
-            }
-
-            if ($mask & multicast) == multicast {
-                assert!(ip!($s).is_multicast());
-            } else {
-                assert!(!ip!($s).is_multicast());
-            }
-
-            if ($mask & doc) == doc {
-                assert!(ip!($s).is_documentation());
-            } else {
-                assert!(!ip!($s).is_documentation());
-            }
-
-            if ($mask & benchmarking) == benchmarking {
-                assert!(ip!($s).is_benchmarking());
-            } else {
-                assert!(!ip!($s).is_benchmarking());
-            }
-        }};
-    }
-
-    let unspec: u8 = 1 << 0;
-    let loopback: u8 = 1 << 1;
-    let global: u8 = 1 << 2;
-    let multicast: u8 = 1 << 3;
-    let doc: u8 = 1 << 4;
-    let benchmarking: u8 = 1 << 5;
-
-    check!("0.0.0.0", unspec);
-    check!("0.0.0.1");
-    check!("0.1.0.0");
-    check!("10.9.8.7");
-    check!("127.1.2.3", loopback);
-    check!("172.31.254.253");
-    check!("169.254.253.242");
-    check!("192.0.2.183", doc);
-    check!("192.1.2.183", global);
-    check!("192.168.254.253");
-    check!("198.51.100.0", doc);
-    check!("203.0.113.0", doc);
-    check!("203.2.113.0", global);
-    check!("224.0.0.0", global | multicast);
-    check!("239.255.255.255", global | multicast);
-    check!("255.255.255.255");
-    // make sure benchmarking addresses are not global
-    check!("198.18.0.0", benchmarking);
-    check!("198.18.54.2", benchmarking);
-    check!("198.19.255.255", benchmarking);
-    // make sure addresses reserved for protocol assignment are not global
-    check!("192.0.0.0");
-    check!("192.0.0.255");
-    check!("192.0.0.100");
-    // make sure reserved addresses are not global
-    check!("240.0.0.0");
-    check!("251.54.1.76");
-    check!("254.255.255.255");
-    // make sure shared addresses are not global
-    check!("100.64.0.0");
-    check!("100.127.255.255");
-    check!("100.100.100.0");
-
-    check!("::", unspec);
-    check!("::1", loopback);
-    check!("::0.0.0.2", global);
-    check!("1::", global);
-    check!("fc00::");
-    check!("fdff:ffff::");
-    check!("fe80:ffff::");
-    check!("febf:ffff::");
-    check!("fec0::", global);
-    check!("ff01::", global | multicast);
-    check!("ff02::", global | multicast);
-    check!("ff03::", global | multicast);
-    check!("ff04::", global | multicast);
-    check!("ff05::", global | multicast);
-    check!("ff08::", global | multicast);
-    check!("ff0e::", global | multicast);
-    check!("2001:db8:85a3::8a2e:370:7334", doc);
-    check!("2001:2::ac32:23ff:21", benchmarking);
-    check!("102:304:506:708:90a:b0c:d0e:f10", global);
-}
-
-#[test]
-fn ipv4_properties() {
-    macro_rules! ip {
-        ($s:expr) => {
-            Ipv4Addr::from_str($s).unwrap()
-        };
-    }
-
-    macro_rules! check {
-        ($s:expr) => {
-            check!($s, 0);
-        };
-
-        ($s:expr, $mask:expr) => {{
-            let unspec: u16 = 1 << 0;
-            let loopback: u16 = 1 << 1;
-            let private: u16 = 1 << 2;
-            let link_local: u16 = 1 << 3;
-            let global: u16 = 1 << 4;
-            let multicast: u16 = 1 << 5;
-            let broadcast: u16 = 1 << 6;
-            let documentation: u16 = 1 << 7;
-            let benchmarking: u16 = 1 << 8;
-            let reserved: u16 = 1 << 10;
-            let shared: u16 = 1 << 11;
-
-            if ($mask & unspec) == unspec {
-                assert!(ip!($s).is_unspecified());
-            } else {
-                assert!(!ip!($s).is_unspecified());
-            }
-
-            if ($mask & loopback) == loopback {
-                assert!(ip!($s).is_loopback());
-            } else {
-                assert!(!ip!($s).is_loopback());
-            }
-
-            if ($mask & private) == private {
-                assert!(ip!($s).is_private());
-            } else {
-                assert!(!ip!($s).is_private());
-            }
-
-            if ($mask & link_local) == link_local {
-                assert!(ip!($s).is_link_local());
-            } else {
-                assert!(!ip!($s).is_link_local());
-            }
-
-            if ($mask & global) == global {
-                assert!(ip!($s).is_global());
-            } else {
-                assert!(!ip!($s).is_global());
-            }
-
-            if ($mask & multicast) == multicast {
-                assert!(ip!($s).is_multicast());
-            } else {
-                assert!(!ip!($s).is_multicast());
-            }
-
-            if ($mask & broadcast) == broadcast {
-                assert!(ip!($s).is_broadcast());
-            } else {
-                assert!(!ip!($s).is_broadcast());
-            }
-
-            if ($mask & documentation) == documentation {
-                assert!(ip!($s).is_documentation());
-            } else {
-                assert!(!ip!($s).is_documentation());
-            }
-
-            if ($mask & benchmarking) == benchmarking {
-                assert!(ip!($s).is_benchmarking());
-            } else {
-                assert!(!ip!($s).is_benchmarking());
-            }
-
-            if ($mask & reserved) == reserved {
-                assert!(ip!($s).is_reserved());
-            } else {
-                assert!(!ip!($s).is_reserved());
-            }
-
-            if ($mask & shared) == shared {
-                assert!(ip!($s).is_shared());
-            } else {
-                assert!(!ip!($s).is_shared());
-            }
-        }};
-    }
-
-    let unspec: u16 = 1 << 0;
-    let loopback: u16 = 1 << 1;
-    let private: u16 = 1 << 2;
-    let link_local: u16 = 1 << 3;
-    let global: u16 = 1 << 4;
-    let multicast: u16 = 1 << 5;
-    let broadcast: u16 = 1 << 6;
-    let documentation: u16 = 1 << 7;
-    let benchmarking: u16 = 1 << 8;
-    let reserved: u16 = 1 << 10;
-    let shared: u16 = 1 << 11;
-
-    check!("0.0.0.0", unspec);
-    check!("0.0.0.1");
-    check!("0.1.0.0");
-    check!("10.9.8.7", private);
-    check!("127.1.2.3", loopback);
-    check!("172.31.254.253", private);
-    check!("169.254.253.242", link_local);
-    check!("192.0.2.183", documentation);
-    check!("192.1.2.183", global);
-    check!("192.168.254.253", private);
-    check!("198.51.100.0", documentation);
-    check!("203.0.113.0", documentation);
-    check!("203.2.113.0", global);
-    check!("224.0.0.0", global | multicast);
-    check!("239.255.255.255", global | multicast);
-    check!("255.255.255.255", broadcast);
-    check!("198.18.0.0", benchmarking);
-    check!("198.18.54.2", benchmarking);
-    check!("198.19.255.255", benchmarking);
-    check!("192.0.0.0");
-    check!("192.0.0.255");
-    check!("192.0.0.100");
-    check!("240.0.0.0", reserved);
-    check!("251.54.1.76", reserved);
-    check!("254.255.255.255", reserved);
-    check!("100.64.0.0", shared);
-    check!("100.127.255.255", shared);
-    check!("100.100.100.0", shared);
-}
-
-#[test]
-fn ipv6_properties() {
-    macro_rules! ip {
-        ($s:expr) => {
-            Ipv6Addr::from_str($s).unwrap()
-        };
-    }
-
-    macro_rules! check {
-        ($s:expr, &[$($octet:expr),*], $mask:expr) => {
-            assert_eq!($s, ip!($s).to_string());
-            let octets = &[$($octet),*];
-            assert_eq!(&ip!($s).octets(), octets);
-            assert_eq!(Ipv6Addr::from(*octets), ip!($s));
-
-            let unspecified: u32 = 1 << 0;
-            let loopback: u32 = 1 << 1;
-            let unique_local: u32 = 1 << 2;
-            let global: u32 = 1 << 3;
-            let unicast_link_local: u32 = 1 << 4;
-            let unicast_global: u32 = 1 << 7;
-            let documentation: u32 = 1 << 8;
-            let benchmarking: u32 = 1 << 16;
-            let multicast_interface_local: u32 = 1 << 9;
-            let multicast_link_local: u32 = 1 << 10;
-            let multicast_realm_local: u32 = 1 << 11;
-            let multicast_admin_local: u32 = 1 << 12;
-            let multicast_site_local: u32 = 1 << 13;
-            let multicast_organization_local: u32 = 1 << 14;
-            let multicast_global: u32 = 1 << 15;
-            let multicast: u32 = multicast_interface_local
-                | multicast_admin_local
-                | multicast_global
-                | multicast_link_local
-                | multicast_realm_local
-                | multicast_site_local
-                | multicast_organization_local;
-
-            if ($mask & unspecified) == unspecified {
-                assert!(ip!($s).is_unspecified());
-            } else {
-                assert!(!ip!($s).is_unspecified());
-            }
-            if ($mask & loopback) == loopback {
-                assert!(ip!($s).is_loopback());
-            } else {
-                assert!(!ip!($s).is_loopback());
-            }
-            if ($mask & unique_local) == unique_local {
-                assert!(ip!($s).is_unique_local());
-            } else {
-                assert!(!ip!($s).is_unique_local());
-            }
-            if ($mask & global) == global {
-                assert!(ip!($s).is_global());
-            } else {
-                assert!(!ip!($s).is_global());
-            }
-            if ($mask & unicast_link_local) == unicast_link_local {
-                assert!(ip!($s).is_unicast_link_local());
-            } else {
-                assert!(!ip!($s).is_unicast_link_local());
-            }
-            if ($mask & unicast_global) == unicast_global {
-                assert!(ip!($s).is_unicast_global());
-            } else {
-                assert!(!ip!($s).is_unicast_global());
-            }
-            if ($mask & documentation) == documentation {
-                assert!(ip!($s).is_documentation());
-            } else {
-                assert!(!ip!($s).is_documentation());
-            }
-            if ($mask & benchmarking) == benchmarking {
-                assert!(ip!($s).is_benchmarking());
-            } else {
-                assert!(!ip!($s).is_benchmarking());
-            }
-            if ($mask & multicast) != 0 {
-                assert!(ip!($s).multicast_scope().is_some());
-                assert!(ip!($s).is_multicast());
-            } else {
-                assert!(ip!($s).multicast_scope().is_none());
-                assert!(!ip!($s).is_multicast());
-            }
-            if ($mask & multicast_interface_local) == multicast_interface_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::InterfaceLocal);
-            }
-            if ($mask & multicast_link_local) == multicast_link_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::LinkLocal);
-            }
-            if ($mask & multicast_realm_local) == multicast_realm_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::RealmLocal);
-            }
-            if ($mask & multicast_admin_local) == multicast_admin_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::AdminLocal);
-            }
-            if ($mask & multicast_site_local) == multicast_site_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::SiteLocal);
-            }
-            if ($mask & multicast_organization_local) == multicast_organization_local {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::OrganizationLocal);
-            }
-            if ($mask & multicast_global) == multicast_global {
-                assert_eq!(ip!($s).multicast_scope().unwrap(),
-                           Ipv6MulticastScope::Global);
-            }
-        }
-    }
-
-    let unspecified: u32 = 1 << 0;
-    let loopback: u32 = 1 << 1;
-    let unique_local: u32 = 1 << 2;
-    let global: u32 = 1 << 3;
-    let unicast_link_local: u32 = 1 << 4;
-    let unicast_global: u32 = 1 << 7;
-    let documentation: u32 = 1 << 8;
-    let benchmarking: u32 = 1 << 16;
-    let multicast_interface_local: u32 = 1 << 9;
-    let multicast_link_local: u32 = 1 << 10;
-    let multicast_realm_local: u32 = 1 << 11;
-    let multicast_admin_local: u32 = 1 << 12;
-    let multicast_site_local: u32 = 1 << 13;
-    let multicast_organization_local: u32 = 1 << 14;
-    let multicast_global: u32 = 1 << 15;
-
-    check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified);
-
-    check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback);
-
-    check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global);
-
-    check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
-
-    check!(
-        "::ffff:127.0.0.1",
-        &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1],
-        unicast_global
-    );
-
-    check!(
-        "64:ff9b:1::",
-        &[0, 0x64, 0xff, 0x9b, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_global
-    );
-
-    check!("100::", &[0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
-    check!("2001::", &[0x20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
-    check!(
-        "2001:1::1",
-        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
-        global | unicast_global
-    );
-
-    check!(
-        "2001:1::2",
-        &[0x20, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
-        global | unicast_global
-    );
-
-    check!(
-        "2001:3::",
-        &[0x20, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        global | unicast_global
-    );
-
-    check!(
-        "2001:4:112::",
-        &[0x20, 1, 0, 4, 1, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        global | unicast_global
-    );
-
-    check!(
-        "2001:20::",
-        &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        global | unicast_global
-    );
-
-    check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
-
-    check!(
-        "2001:200::",
-        &[0x20, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        global | unicast_global
-    );
-
-    check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
-
-    check!(
-        "fdff:ffff::",
-        &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unique_local
-    );
-
-    check!(
-        "fe80:ffff::",
-        &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_link_local
-    );
-
-    check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
-
-    check!(
-        "febf:ffff::",
-        &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_link_local
-    );
-
-    check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
-
-    check!(
-        "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-        &[
-            0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-            0xff, 0xff
-        ],
-        unicast_link_local
-    );
-
-    check!(
-        "fe80::ffff:ffff:ffff:ffff",
-        &[
-            0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-            0xff, 0xff
-        ],
-        unicast_link_local
-    );
-
-    check!(
-        "fe80:0:0:1::",
-        &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_link_local
-    );
-
-    check!(
-        "fec0::",
-        &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_global | global
-    );
-
-    check!(
-        "ff01::",
-        &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_interface_local | global
-    );
-
-    check!(
-        "ff02::",
-        &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_link_local | global
-    );
-
-    check!(
-        "ff03::",
-        &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_realm_local | global
-    );
-
-    check!(
-        "ff04::",
-        &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_admin_local | global
-    );
-
-    check!(
-        "ff05::",
-        &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_site_local | global
-    );
-
-    check!(
-        "ff08::",
-        &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_organization_local | global
-    );
-
-    check!(
-        "ff0e::",
-        &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        multicast_global | global
-    );
-
-    check!(
-        "2001:db8:85a3::8a2e:370:7334",
-        &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34],
-        documentation
-    );
-
-    check!(
-        "2001:2::ac32:23ff:21",
-        &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21],
-        benchmarking
-    );
-
-    check!(
-        "102:304:506:708:90a:b0c:d0e:f10",
-        &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
-        global | unicast_global
-    );
-}
+use crate::net::test::{sa4, tsa};
+use crate::net::Ipv4Addr;
 
 #[test]
 fn to_socket_addr_socketaddr() {
     let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345);
     assert_eq!(Ok(vec![a]), tsa(a));
 }
-
-#[test]
-fn test_ipv4_to_int() {
-    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
-    assert_eq!(u32::from(a), 0x11223344);
-}
-
-#[test]
-fn test_int_to_ipv4() {
-    let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44);
-    assert_eq!(Ipv4Addr::from(0x11223344), a);
-}
-
-#[test]
-fn test_ipv6_to_int() {
-    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
-    assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128);
-}
-
-#[test]
-fn test_int_to_ipv6() {
-    let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11);
-    assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a);
-}
-
-#[test]
-fn ipv4_from_constructors() {
-    assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1));
-    assert!(Ipv4Addr::LOCALHOST.is_loopback());
-    assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0));
-    assert!(Ipv4Addr::UNSPECIFIED.is_unspecified());
-    assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255));
-    assert!(Ipv4Addr::BROADCAST.is_broadcast());
-}
-
-#[test]
-fn ipv6_from_constructors() {
-    assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    assert!(Ipv6Addr::LOCALHOST.is_loopback());
-    assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
-    assert!(Ipv6Addr::UNSPECIFIED.is_unspecified());
-}
-
-#[test]
-fn ipv4_from_octets() {
-    assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1))
-}
-
-#[test]
-fn ipv6_from_segments() {
-    let from_u16s =
-        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
-    let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff);
-    assert_eq!(new, from_u16s);
-}
-
-#[test]
-fn ipv6_from_octets() {
-    let from_u16s =
-        Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]);
-    let from_u8s = Ipv6Addr::from([
-        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
-        0xff,
-    ]);
-    assert_eq!(from_u16s, from_u8s);
-}
-
-#[test]
-fn cmp() {
-    let v41 = Ipv4Addr::new(100, 64, 3, 3);
-    let v42 = Ipv4Addr::new(192, 0, 2, 2);
-    let v61 = "2001:db8:f00::1002".parse::<Ipv6Addr>().unwrap();
-    let v62 = "2001:db8:f00::2001".parse::<Ipv6Addr>().unwrap();
-    assert!(v41 < v42);
-    assert!(v61 < v62);
-
-    assert_eq!(v41, IpAddr::V4(v41));
-    assert_eq!(v61, IpAddr::V6(v61));
-    assert!(v41 != IpAddr::V4(v42));
-    assert!(v61 != IpAddr::V6(v62));
-
-    assert!(v41 < IpAddr::V4(v42));
-    assert!(v61 < IpAddr::V6(v62));
-    assert!(IpAddr::V4(v41) < v42);
-    assert!(IpAddr::V6(v61) < v62);
-
-    assert!(v41 < IpAddr::V6(v61));
-    assert!(IpAddr::V4(v41) < v61);
-}
-
-#[test]
-fn is_v4() {
-    let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3));
-    assert!(ip.is_ipv4());
-    assert!(!ip.is_ipv6());
-}
-
-#[test]
-fn is_v6() {
-    let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678));
-    assert!(!ip.is_ipv4());
-    assert!(ip.is_ipv6());
-}
-
-#[test]
-fn ipv4_const() {
-    // test that the methods of `Ipv4Addr` are usable in a const context
-
-    const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
-    assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST);
-
-    const OCTETS: [u8; 4] = IP_ADDRESS.octets();
-    assert_eq!(OCTETS, [127, 0, 0, 1]);
-
-    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
-    assert!(!IS_UNSPECIFIED);
-
-    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
-    assert!(IS_LOOPBACK);
-
-    const IS_PRIVATE: bool = IP_ADDRESS.is_private();
-    assert!(!IS_PRIVATE);
-
-    const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local();
-    assert!(!IS_LINK_LOCAL);
-
-    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
-    assert!(!IS_GLOBAL);
-
-    const IS_SHARED: bool = IP_ADDRESS.is_shared();
-    assert!(!IS_SHARED);
-
-    const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
-    assert!(!IS_BENCHMARKING);
-
-    const IS_RESERVED: bool = IP_ADDRESS.is_reserved();
-    assert!(!IS_RESERVED);
-
-    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
-    assert!(!IS_MULTICAST);
-
-    const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast();
-    assert!(!IS_BROADCAST);
-
-    const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
-    assert!(!IS_DOCUMENTATION);
-
-    const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible();
-    assert_eq!(
-        IP_V6_COMPATIBLE,
-        Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])
-    );
-
-    const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped();
-    assert_eq!(
-        IP_V6_MAPPED,
-        Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])
-    );
-}
-
-#[test]
-fn ipv6_const() {
-    // test that the methods of `Ipv6Addr` are usable in a const context
-
-    const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
-    assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST);
-
-    const SEGMENTS: [u16; 8] = IP_ADDRESS.segments();
-    assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]);
-
-    const OCTETS: [u8; 16] = IP_ADDRESS.octets();
-    assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
-
-    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
-    assert!(!IS_UNSPECIFIED);
-
-    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
-    assert!(IS_LOOPBACK);
-
-    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
-    assert!(!IS_GLOBAL);
-
-    const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
-    assert!(!IS_UNIQUE_LOCAL);
-
-    const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
-    assert!(!IS_UNICAST_LINK_LOCAL);
-
-    const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation();
-    assert!(!IS_DOCUMENTATION);
-
-    const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking();
-    assert!(!IS_BENCHMARKING);
-
-    const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global();
-    assert!(!IS_UNICAST_GLOBAL);
-
-    const MULTICAST_SCOPE: Option<Ipv6MulticastScope> = IP_ADDRESS.multicast_scope();
-    assert_eq!(MULTICAST_SCOPE, None);
-
-    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
-    assert!(!IS_MULTICAST);
-
-    const IP_V4: Option<Ipv4Addr> = IP_ADDRESS.to_ipv4();
-    assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1));
-}
-
-#[test]
-fn ip_const() {
-    // test that the methods of `IpAddr` are usable in a const context
-
-    const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
-
-    const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified();
-    assert!(!IS_UNSPECIFIED);
-
-    const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback();
-    assert!(IS_LOOPBACK);
-
-    const IS_GLOBAL: bool = IP_ADDRESS.is_global();
-    assert!(!IS_GLOBAL);
-
-    const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
-    assert!(!IS_MULTICAST);
-
-    const IS_IP_V4: bool = IP_ADDRESS.is_ipv4();
-    assert!(IS_IP_V4);
-
-    const IS_IP_V6: bool = IP_ADDRESS.is_ipv6();
-    assert!(!IS_IP_V6);
-}
-
-#[test]
-fn structural_match() {
-    // test that all IP types can be structurally matched upon
-
-    const IPV4: Ipv4Addr = Ipv4Addr::LOCALHOST;
-    match IPV4 {
-        Ipv4Addr::LOCALHOST => {}
-        _ => unreachable!(),
-    }
-
-    const IPV6: Ipv6Addr = Ipv6Addr::LOCALHOST;
-    match IPV6 {
-        Ipv6Addr::LOCALHOST => {}
-        _ => unreachable!(),
-    }
-
-    const IP: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
-    match IP {
-        IpAddr::V4(Ipv4Addr::LOCALHOST) => {}
-        _ => unreachable!(),
-    }
-}
diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs
index 19d90e7ec38..bcab15db35b 100644
--- a/library/std/src/net/mod.rs
+++ b/library/std/src/net/mod.rs
@@ -26,8 +26,6 @@ use crate::io::{self, ErrorKind};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::ip_addr::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use self::parser::AddrParseError;
-#[stable(feature = "rust1", since = "1.0.0")]
 pub use self::socket_addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
 #[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
 pub use self::tcp::IntoIncoming;
@@ -35,10 +33,10 @@ pub use self::tcp::IntoIncoming;
 pub use self::tcp::{Incoming, TcpListener, TcpStream};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::udp::UdpSocket;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::net::AddrParseError;
 
-mod display_buffer;
 mod ip_addr;
-mod parser;
 mod socket_addr;
 mod tcp;
 #[cfg(test)]
diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs
index 1264bae809b..421fed9077c 100644
--- a/library/std/src/net/socket_addr.rs
+++ b/library/std/src/net/socket_addr.rs
@@ -1,9 +1,7 @@
+// Tests for this module
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
 
-use crate::cmp::Ordering;
-use crate::fmt::{self, Write};
-use crate::hash;
 use crate::io;
 use crate::iter;
 use crate::mem;
@@ -15,533 +13,23 @@ use crate::sys_common::net::LookupHost;
 use crate::sys_common::{FromInner, IntoInner};
 use crate::vec;
 
-use super::display_buffer::DisplayBuffer;
-
-/// An internet socket address, either IPv4 or IPv6.
-///
-/// Internet socket addresses consist of an [IP address], a 16-bit port number, as well
-/// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and
-/// [`SocketAddrV6`]'s respective documentation for more details.
-///
-/// The size of a `SocketAddr` instance may vary depending on the target operating
-/// system.
-///
-/// [IP address]: IpAddr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-///
-/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-///
-/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
-/// assert_eq!(socket.port(), 8080);
-/// assert_eq!(socket.is_ipv4(), true);
-/// ```
-#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub enum SocketAddr {
-    /// An IPv4 socket address.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    V4(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV4),
-    /// An IPv6 socket address.
-    #[stable(feature = "rust1", since = "1.0.0")]
-    V6(#[stable(feature = "rust1", since = "1.0.0")] SocketAddrV6),
-}
-
-/// An IPv4 socket address.
-///
-/// IPv4 socket addresses consist of an [`IPv4` address] and a 16-bit port number, as
-/// stated in [IETF RFC 793].
-///
-/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
-///
-/// The size of a `SocketAddrV4` struct may vary depending on the target operating
-/// system. Do not assume that this type has the same memory layout as the underlying
-/// system representation.
-///
-/// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
-/// [`IPv4` address]: Ipv4Addr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{Ipv4Addr, SocketAddrV4};
-///
-/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-///
-/// assert_eq!("127.0.0.1:8080".parse(), Ok(socket));
-/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
-/// assert_eq!(socket.port(), 8080);
-/// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SocketAddrV4 {
-    ip: Ipv4Addr,
-    port: u16,
-}
-
-/// An IPv6 socket address.
-///
-/// IPv6 socket addresses consist of an [`IPv6` address], a 16-bit port number, as well
-/// as fields containing the traffic class, the flow label, and a scope identifier
-/// (see [IETF RFC 2553, Section 3.3] for more details).
-///
-/// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses.
-///
-/// The size of a `SocketAddrV6` struct may vary depending on the target operating
-/// system. Do not assume that this type has the same memory layout as the underlying
-/// system representation.
-///
-/// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-/// [`IPv6` address]: Ipv6Addr
-///
-/// # Examples
-///
-/// ```
-/// use std::net::{Ipv6Addr, SocketAddrV6};
-///
-/// let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-///
-/// assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket));
-/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
-/// assert_eq!(socket.port(), 8080);
-/// ```
-#[derive(Copy, Clone, Eq, PartialEq)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct SocketAddrV6 {
-    ip: Ipv6Addr,
-    port: u16,
-    flowinfo: u32,
-    scope_id: u32,
-}
-
-impl SocketAddr {
-    /// Creates a new socket address from an [IP address] and a port number.
-    ///
-    /// [IP address]: IpAddr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
-    /// assert_eq!(socket.port(), 8080);
-    /// ```
-    #[stable(feature = "ip_addr", since = "1.7.0")]
-    #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn new(ip: IpAddr, port: u16) -> SocketAddr {
-        match ip {
-            IpAddr::V4(a) => SocketAddr::V4(SocketAddrV4::new(a, port)),
-            IpAddr::V6(a) => SocketAddr::V6(SocketAddrV6::new(a, port, 0, 0)),
-        }
-    }
-
-    /// Returns the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
-    /// ```
-    #[must_use]
-    #[stable(feature = "ip_addr", since = "1.7.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn ip(&self) -> IpAddr {
-        match *self {
-            SocketAddr::V4(ref a) => IpAddr::V4(*a.ip()),
-            SocketAddr::V6(ref a) => IpAddr::V6(*a.ip()),
-        }
-    }
-
-    /// Changes the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
-    /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_ip(&mut self, new_ip: IpAddr) {
-        // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
-        match (self, new_ip) {
-            (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
-            (&mut SocketAddr::V6(ref mut a), IpAddr::V6(new_ip)) => a.set_ip(new_ip),
-            (self_, new_ip) => *self_ = Self::new(new_ip, self_.port()),
-        }
-    }
-
-    /// Returns the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// assert_eq!(socket.port(), 8080);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn port(&self) -> u16 {
-        match *self {
-            SocketAddr::V4(ref a) => a.port(),
-            SocketAddr::V6(ref a) => a.port(),
-        }
-    }
-
-    /// Changes the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let mut socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// socket.set_port(1025);
-    /// assert_eq!(socket.port(), 1025);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_port(&mut self, new_port: u16) {
-        match *self {
-            SocketAddr::V4(ref mut a) => a.set_port(new_port),
-            SocketAddr::V6(ref mut a) => a.set_port(new_port),
-        }
-    }
-
-    /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
-    /// [`IPv4` address], and [`false`] otherwise.
-    ///
-    /// [IP address]: IpAddr
-    /// [`IPv4` address]: IpAddr::V4
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
-    /// assert_eq!(socket.is_ipv4(), true);
-    /// assert_eq!(socket.is_ipv6(), false);
-    /// ```
-    #[must_use]
-    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn is_ipv4(&self) -> bool {
-        matches!(*self, SocketAddr::V4(_))
-    }
-
-    /// Returns [`true`] if the [IP address] in this `SocketAddr` is an
-    /// [`IPv6` address], and [`false`] otherwise.
-    ///
-    /// [IP address]: IpAddr
-    /// [`IPv6` address]: IpAddr::V6
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{IpAddr, Ipv6Addr, SocketAddr};
-    ///
-    /// let socket = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 0, 1)), 8080);
-    /// assert_eq!(socket.is_ipv4(), false);
-    /// assert_eq!(socket.is_ipv6(), true);
-    /// ```
-    #[must_use]
-    #[stable(feature = "sockaddr_checker", since = "1.16.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn is_ipv6(&self) -> bool {
-        matches!(*self, SocketAddr::V6(_))
-    }
-}
-
-impl SocketAddrV4 {
-    /// Creates a new socket address from an [`IPv4` address] and a port number.
-    ///
-    /// [`IPv4` address]: Ipv4Addr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
-        SocketAddrV4 { ip, port }
-    }
-
-    /// Returns the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn ip(&self) -> &Ipv4Addr {
-        &self.ip
-    }
-
-    /// Changes the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
-    /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
-        self.ip = new_ip;
-    }
-
-    /// Returns the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// assert_eq!(socket.port(), 8080);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn port(&self) -> u16 {
-        self.port
-    }
-
-    /// Changes the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV4, Ipv4Addr};
-    ///
-    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
-    /// socket.set_port(4242);
-    /// assert_eq!(socket.port(), 4242);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_port(&mut self, new_port: u16) {
-        self.port = new_port;
-    }
-}
-
-impl SocketAddrV6 {
-    /// Creates a new socket address from an [`IPv6` address], a 16-bit port number,
-    /// and the `flowinfo` and `scope_id` fields.
-    ///
-    /// For more information on the meaning and layout of the `flowinfo` and `scope_id`
-    /// parameters, see [IETF RFC 2553, Section 3.3].
-    ///
-    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-    /// [`IPv6` address]: Ipv6Addr
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32) -> SocketAddrV6 {
-        SocketAddrV6 { ip, port, flowinfo, scope_id }
-    }
-
-    /// Returns the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn ip(&self) -> &Ipv6Addr {
-        &self.ip
-    }
-
-    /// Changes the IP address associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
-    /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
-        self.ip = new_ip;
-    }
-
-    /// Returns the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// assert_eq!(socket.port(), 8080);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn port(&self) -> u16 {
-        self.port
-    }
-
-    /// Changes the port number associated with this socket address.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
-    /// socket.set_port(4242);
-    /// assert_eq!(socket.port(), 4242);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_port(&mut self, new_port: u16) {
-        self.port = new_port;
-    }
-
-    /// Returns the flow information associated with this address.
-    ///
-    /// This information corresponds to the `sin6_flowinfo` field in C's `netinet/in.h`,
-    /// as specified in [IETF RFC 2553, Section 3.3].
-    /// It combines information about the flow label and the traffic class as specified
-    /// in [IETF RFC 2460], respectively [Section 6] and [Section 7].
-    ///
-    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-    /// [IETF RFC 2460]: https://tools.ietf.org/html/rfc2460
-    /// [Section 6]: https://tools.ietf.org/html/rfc2460#section-6
-    /// [Section 7]: https://tools.ietf.org/html/rfc2460#section-7
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
-    /// assert_eq!(socket.flowinfo(), 10);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn flowinfo(&self) -> u32 {
-        self.flowinfo
-    }
-
-    /// Changes the flow information associated with this socket address.
-    ///
-    /// See [`SocketAddrV6::flowinfo`]'s documentation for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
-    /// socket.set_flowinfo(56);
-    /// assert_eq!(socket.flowinfo(), 56);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
-        self.flowinfo = new_flowinfo;
-    }
-
-    /// Returns the scope ID associated with this address.
-    ///
-    /// This information corresponds to the `sin6_scope_id` field in C's `netinet/in.h`,
-    /// as specified in [IETF RFC 2553, Section 3.3].
-    ///
-    /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
-    /// assert_eq!(socket.scope_id(), 78);
-    /// ```
-    #[must_use]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_socketaddr", since = "CURRENT_RUSTC_VERSION")]
-    pub const fn scope_id(&self) -> u32 {
-        self.scope_id
-    }
-
-    /// Changes the scope ID associated with this socket address.
-    ///
-    /// See [`SocketAddrV6::scope_id`]'s documentation for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::net::{SocketAddrV6, Ipv6Addr};
-    ///
-    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
-    /// socket.set_scope_id(42);
-    /// assert_eq!(socket.scope_id(), 42);
-    /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
-    pub fn set_scope_id(&mut self, new_scope_id: u32) {
-        self.scope_id = new_scope_id;
-    }
-}
+pub use core::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
 
 impl FromInner<c::sockaddr_in> for SocketAddrV4 {
     fn from_inner(addr: c::sockaddr_in) -> SocketAddrV4 {
-        SocketAddrV4 { ip: Ipv4Addr::from_inner(addr.sin_addr), port: u16::from_be(addr.sin_port) }
+        SocketAddrV4::new(Ipv4Addr::from_inner(addr.sin_addr), u16::from_be(addr.sin_port))
     }
 }
 
 impl FromInner<c::sockaddr_in6> for SocketAddrV6 {
     fn from_inner(addr: c::sockaddr_in6) -> SocketAddrV6 {
-        SocketAddrV6 {
-            ip: Ipv6Addr::from_inner(addr.sin6_addr),
-            port: u16::from_be(addr.sin6_port),
-            flowinfo: addr.sin6_flowinfo,
-            scope_id: addr.sin6_scope_id,
-        }
+        SocketAddrV6::new(
+            Ipv6Addr::from_inner(addr.sin6_addr),
+            u16::from_be(addr.sin6_port),
+            addr.sin6_flowinfo,
+            addr.sin6_scope_id,
+        )
     }
 }
 
@@ -549,8 +37,8 @@ impl IntoInner<c::sockaddr_in> for SocketAddrV4 {
     fn into_inner(self) -> c::sockaddr_in {
         c::sockaddr_in {
             sin_family: c::AF_INET as c::sa_family_t,
-            sin_port: self.port.to_be(),
-            sin_addr: self.ip.into_inner(),
+            sin_port: self.port().to_be(),
+            sin_addr: self.ip().into_inner(),
             ..unsafe { mem::zeroed() }
         }
     }
@@ -560,162 +48,15 @@ impl IntoInner<c::sockaddr_in6> for SocketAddrV6 {
     fn into_inner(self) -> c::sockaddr_in6 {
         c::sockaddr_in6 {
             sin6_family: c::AF_INET6 as c::sa_family_t,
-            sin6_port: self.port.to_be(),
-            sin6_addr: self.ip.into_inner(),
-            sin6_flowinfo: self.flowinfo,
-            sin6_scope_id: self.scope_id,
+            sin6_port: self.port().to_be(),
+            sin6_addr: self.ip().into_inner(),
+            sin6_flowinfo: self.flowinfo(),
+            sin6_scope_id: self.scope_id(),
             ..unsafe { mem::zeroed() }
         }
     }
 }
 
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<SocketAddrV4> for SocketAddr {
-    /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
-    fn from(sock4: SocketAddrV4) -> SocketAddr {
-        SocketAddr::V4(sock4)
-    }
-}
-
-#[stable(feature = "ip_from_ip", since = "1.16.0")]
-impl From<SocketAddrV6> for SocketAddr {
-    /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
-    fn from(sock6: SocketAddrV6) -> SocketAddr {
-        SocketAddr::V6(sock6)
-    }
-}
-
-#[stable(feature = "addr_from_into_ip", since = "1.17.0")]
-impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
-    /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`].
-    ///
-    /// This conversion creates a [`SocketAddr::V4`] for an [`IpAddr::V4`]
-    /// and creates a [`SocketAddr::V6`] for an [`IpAddr::V6`].
-    ///
-    /// `u16` is treated as port of the newly created [`SocketAddr`].
-    fn from(pieces: (I, u16)) -> SocketAddr {
-        SocketAddr::new(pieces.0.into(), pieces.1)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddr {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            SocketAddr::V4(ref a) => a.fmt(f),
-            SocketAddr::V6(ref a) => a.fmt(f),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddr {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddrV4 {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // If there are no alignment requirements, write the socket address directly to `f`.
-        // Otherwise, write it to a local buffer and then use `f.pad`.
-        if f.precision().is_none() && f.width().is_none() {
-            write!(f, "{}:{}", self.ip(), self.port())
-        } else {
-            const LONGEST_IPV4_SOCKET_ADDR: &str = "255.255.255.255:65536";
-
-            let mut buf = DisplayBuffer::<{ LONGEST_IPV4_SOCKET_ADDR.len() }>::new();
-            // Buffer is long enough for the longest possible IPv4 socket address, so this should never fail.
-            write!(buf, "{}:{}", self.ip(), self.port()).unwrap();
-
-            f.pad(buf.as_str())
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddrV4 {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Display for SocketAddrV6 {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // If there are no alignment requirements, write the socket address directly to `f`.
-        // Otherwise, write it to a local buffer and then use `f.pad`.
-        if f.precision().is_none() && f.width().is_none() {
-            match self.scope_id() {
-                0 => write!(f, "[{}]:{}", self.ip(), self.port()),
-                scope_id => write!(f, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
-            }
-        } else {
-            const LONGEST_IPV6_SOCKET_ADDR: &str =
-                "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%4294967296]:65536";
-
-            let mut buf = DisplayBuffer::<{ LONGEST_IPV6_SOCKET_ADDR.len() }>::new();
-            match self.scope_id() {
-                0 => write!(buf, "[{}]:{}", self.ip(), self.port()),
-                scope_id => write!(buf, "[{}%{}]:{}", self.ip(), scope_id, self.port()),
-            }
-            // Buffer is long enough for the longest possible IPv6 socket address, so this should never fail.
-            .unwrap();
-
-            f.pad(buf.as_str())
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for SocketAddrV6 {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self, fmt)
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV4 {
-    fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl PartialOrd for SocketAddrV6 {
-    fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV4 {
-    fn cmp(&self, other: &SocketAddrV4) -> Ordering {
-        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
-    }
-}
-
-#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
-impl Ord for SocketAddrV6 {
-    fn cmp(&self, other: &SocketAddrV6) -> Ordering {
-        self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV4 {
-    fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        (self.port, self.ip).hash(s)
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl hash::Hash for SocketAddrV6 {
-    fn hash<H: hash::Hasher>(&self, s: &mut H) {
-        (self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
-    }
-}
-
 /// A trait for objects which can be converted or resolved to one or more
 /// [`SocketAddr`] values.
 ///
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 1d0ab772739..5d150eca00e 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -6,13 +6,15 @@
 
 use crate::ffi::CStr;
 use crate::mem;
-use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort};
+use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort};
 use crate::os::windows::io::{BorrowedHandle, HandleOrInvalid, HandleOrNull};
 use crate::ptr;
 use core::ffi::NonZero_c_ulong;
 
 use libc::{c_void, size_t, wchar_t};
 
+pub use crate::os::raw::c_int;
+
 #[path = "c/errors.rs"] // c.rs is included from two places so we need to specify this
 mod errors;
 pub use errors::*;
@@ -47,16 +49,19 @@ pub type ACCESS_MASK = DWORD;
 
 pub type LPBOOL = *mut BOOL;
 pub type LPBYTE = *mut BYTE;
+pub type LPCCH = *const CHAR;
 pub type LPCSTR = *const CHAR;
+pub type LPCWCH = *const WCHAR;
 pub type LPCWSTR = *const WCHAR;
+pub type LPCVOID = *const c_void;
 pub type LPDWORD = *mut DWORD;
 pub type LPHANDLE = *mut HANDLE;
 pub type LPOVERLAPPED = *mut OVERLAPPED;
 pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
 pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
 pub type LPSTARTUPINFO = *mut STARTUPINFO;
+pub type LPSTR = *mut CHAR;
 pub type LPVOID = *mut c_void;
-pub type LPCVOID = *const c_void;
 pub type LPWCH = *mut WCHAR;
 pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
 pub type LPWSADATA = *mut WSADATA;
@@ -132,6 +137,10 @@ pub const MAX_PATH: usize = 260;
 
 pub const FILE_TYPE_PIPE: u32 = 3;
 
+pub const CP_UTF8: DWORD = 65001;
+pub const MB_ERR_INVALID_CHARS: DWORD = 0x08;
+pub const WC_ERR_INVALID_CHARS: DWORD = 0x80;
+
 #[repr(C)]
 #[derive(Copy)]
 pub struct WIN32_FIND_DATAW {
@@ -1147,6 +1156,25 @@ extern "system" {
         lpFilePart: *mut LPWSTR,
     ) -> DWORD;
     pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD;
+
+    pub fn MultiByteToWideChar(
+        CodePage: UINT,
+        dwFlags: DWORD,
+        lpMultiByteStr: LPCCH,
+        cbMultiByte: c_int,
+        lpWideCharStr: LPWSTR,
+        cchWideChar: c_int,
+    ) -> c_int;
+    pub fn WideCharToMultiByte(
+        CodePage: UINT,
+        dwFlags: DWORD,
+        lpWideCharStr: LPCWCH,
+        cchWideChar: c_int,
+        lpMultiByteStr: LPSTR,
+        cbMultiByte: c_int,
+        lpDefaultChar: LPCCH,
+        lpUsedDefaultChar: LPBOOL,
+    ) -> c_int;
 }
 
 #[link(name = "ws2_32")]
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index c2cd48470bd..32c6ccffb7a 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -169,14 +169,27 @@ fn write(
 }
 
 fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usize> {
+    debug_assert!(!utf8.is_empty());
+
     let mut utf16 = [MaybeUninit::<u16>::uninit(); MAX_BUFFER_SIZE / 2];
-    let mut len_utf16 = 0;
-    for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) {
-        *dest = MaybeUninit::new(chr);
-        len_utf16 += 1;
-    }
-    // Safety: We've initialized `len_utf16` values.
-    let utf16: &[u16] = unsafe { MaybeUninit::slice_assume_init_ref(&utf16[..len_utf16]) };
+    let utf8 = &utf8[..utf8.floor_char_boundary(utf16.len())];
+
+    let utf16: &[u16] = unsafe {
+        // Note that this theoretically checks validity twice in the (most common) case
+        // where the underlying byte sequence is valid utf-8 (given the check in `write()`).
+        let result = c::MultiByteToWideChar(
+            c::CP_UTF8,                      // CodePage
+            c::MB_ERR_INVALID_CHARS,         // dwFlags
+            utf8.as_ptr() as c::LPCCH,       // lpMultiByteStr
+            utf8.len() as c::c_int,          // cbMultiByte
+            utf16.as_mut_ptr() as c::LPWSTR, // lpWideCharStr
+            utf16.len() as c::c_int,         // cchWideChar
+        );
+        assert!(result != 0, "Unexpected error in MultiByteToWideChar");
+
+        // Safety: MultiByteToWideChar initializes `result` values.
+        MaybeUninit::slice_assume_init_ref(&utf16[..result as usize])
+    };
 
     let mut written = write_u16s(handle, &utf16)?;
 
@@ -189,8 +202,8 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
         // a missing surrogate can be produced (and also because of the UTF-8 validation above),
         // write the missing surrogate out now.
         // Buffering it would mean we have to lie about the number of bytes written.
-        let first_char_remaining = utf16[written];
-        if first_char_remaining >= 0xDCEE && first_char_remaining <= 0xDFFF {
+        let first_code_unit_remaining = utf16[written];
+        if first_code_unit_remaining >= 0xDCEE && first_code_unit_remaining <= 0xDFFF {
             // low surrogate
             // We just hope this works, and give up otherwise
             let _ = write_u16s(handle, &utf16[written..written + 1]);
@@ -212,6 +225,7 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
 }
 
 fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
+    debug_assert!(data.len() < u32::MAX as usize);
     let mut written = 0;
     cvt(unsafe {
         c::WriteConsoleW(
@@ -365,26 +379,32 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
     Ok(amount as usize)
 }
 
-#[allow(unused)]
 fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
-    let mut written = 0;
-    for chr in char::decode_utf16(utf16.iter().cloned()) {
-        match chr {
-            Ok(chr) => {
-                chr.encode_utf8(&mut utf8[written..]);
-                written += chr.len_utf8();
-            }
-            Err(_) => {
-                // We can't really do any better than forget all data and return an error.
-                return Err(io::const_io_error!(
-                    io::ErrorKind::InvalidData,
-                    "Windows stdin in console mode does not support non-UTF-16 input; \
-                     encountered unpaired surrogate",
-                ));
-            }
-        }
+    debug_assert!(utf16.len() <= c::c_int::MAX as usize);
+    debug_assert!(utf8.len() <= c::c_int::MAX as usize);
+
+    let result = unsafe {
+        c::WideCharToMultiByte(
+            c::CP_UTF8,                    // CodePage
+            c::WC_ERR_INVALID_CHARS,       // dwFlags
+            utf16.as_ptr(),                // lpWideCharStr
+            utf16.len() as c::c_int,       // cchWideChar
+            utf8.as_mut_ptr() as c::LPSTR, // lpMultiByteStr
+            utf8.len() as c::c_int,        // cbMultiByte
+            ptr::null(),                   // lpDefaultChar
+            ptr::null_mut(),               // lpUsedDefaultChar
+        )
+    };
+    if result == 0 {
+        // We can't really do any better than forget all data and return an error.
+        Err(io::const_io_error!(
+            io::ErrorKind::InvalidData,
+            "Windows stdin in console mode does not support non-UTF-16 input; \
+            encountered unpaired surrogate",
+        ))
+    } else {
+        Ok(result as usize)
     }
-    Ok(written)
 }
 
 impl IncompleteUtf8 {
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 4a0ba592577..e861d520c53 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -50,6 +50,7 @@ dependencies = [
  "opener",
  "pretty_assertions",
  "serde",
+ "serde_derive",
  "serde_json",
  "sha2",
  "sysinfo",
@@ -564,9 +565,6 @@ name = "serde"
 version = "1.0.137"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
-dependencies = [
- "serde_derive",
-]
 
 [[package]]
 name = "serde_derive"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 22ceeca941e..663987f113c 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -39,7 +39,10 @@ cc = "1.0.69"
 libc = "0.2"
 hex = "0.4"
 object = { version = "0.29.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
-serde = { version = "1.0.8", features = ["derive"] }
+serde = "1.0.137"
+# Directly use serde_derive rather than through the derive feature of serde to allow building both
+# in parallel and to allow serde_json and toml to start building as soon as serde has been built.
+serde_derive = "1.0.137"
 serde_json = "1.0.2"
 sha2 = "0.10"
 tar = "0.4"
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 348d22a9ce6..8b80dfc0f9b 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -16,7 +16,7 @@ use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 use std::str;
 
-use serde::Deserialize;
+use serde_derive::Deserialize;
 
 use crate::builder::crate_description;
 use crate::builder::Cargo;
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 4a563bc396d..05e74254949 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -25,6 +25,7 @@ use crate::flags::{Color, Flags};
 use crate::util::{exe, output, t};
 use once_cell::sync::OnceCell;
 use serde::{Deserialize, Deserializer};
+use serde_derive::Deserialize;
 
 macro_rules! check_ci_llvm {
     ($name:expr) => {
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index ae72a42973c..6d5753e8a6d 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -87,7 +87,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, Str
     get_git_modified_files(Some(&build.config.src), &vec!["rs"])
 }
 
-#[derive(serde::Deserialize)]
+#[derive(serde_derive::Deserialize)]
 struct RustfmtConfig {
     ignore: Vec<String>,
 }
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs
index e193e70a0c4..bba4d65e8c3 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/metadata.rs
@@ -1,7 +1,7 @@
 use std::path::PathBuf;
 use std::process::Command;
 
-use serde::Deserialize;
+use serde_derive::Deserialize;
 
 use crate::cache::INTERNER;
 use crate::util::output;
diff --git a/src/bootstrap/metrics.rs b/src/bootstrap/metrics.rs
index c823dc79684..2e62c950709 100644
--- a/src/bootstrap/metrics.rs
+++ b/src/bootstrap/metrics.rs
@@ -7,7 +7,7 @@
 use crate::builder::Step;
 use crate::util::t;
 use crate::Build;
-use serde::{Deserialize, Serialize};
+use serde_derive::{Deserialize, Serialize};
 use std::cell::RefCell;
 use std::fs::File;
 use std::io::BufWriter;
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index 1969e0b6f87..7aab88a1a73 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -1,6 +1,6 @@
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::util::t;
-use serde::{Deserialize, Serialize};
+use serde_derive::{Deserialize, Serialize};
 use std::collections::HashMap;
 use std::env;
 use std::fmt;
diff --git a/tests/ui/resolve/issue-108529.rs b/tests/ui/resolve/issue-108529.rs
new file mode 100644
index 00000000000..8e3aafab6aa
--- /dev/null
+++ b/tests/ui/resolve/issue-108529.rs
@@ -0,0 +1,8 @@
+#![allow(nonstandard_style)]
+use f::f::f; //~ ERROR
+
+trait f {
+    extern "C" fn f();
+}
+
+fn main() {}
diff --git a/tests/ui/resolve/issue-108529.stderr b/tests/ui/resolve/issue-108529.stderr
new file mode 100644
index 00000000000..cf4e4759c37
--- /dev/null
+++ b/tests/ui/resolve/issue-108529.stderr
@@ -0,0 +1,9 @@
+error[E0432]: unresolved import `f::f`
+  --> $DIR/issue-108529.rs:2:8
+   |
+LL | use f::f::f;
+   |        ^ expected type, found associated function `f` in `f`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/tests/ui/rust-2018/remove-extern-crate.fixed b/tests/ui/rust-2018/remove-extern-crate.fixed
index 832632268fb..15e0ccc5256 100644
--- a/tests/ui/rust-2018/remove-extern-crate.fixed
+++ b/tests/ui/rust-2018/remove-extern-crate.fixed
@@ -23,6 +23,7 @@ extern crate alloc;
 fn main() {
     another_name::mem::drop(3);
     another::foo();
+    with_visibility::foo();
     remove_extern_crate::foo!();
     bar!();
     alloc::vec![5];
@@ -37,3 +38,12 @@ mod another {
         remove_extern_crate::foo!();
     }
 }
+
+mod with_visibility {
+    pub use core; //~ WARNING `extern crate` is not idiomatic
+
+    pub fn foo() {
+        core::mem::drop(4);
+        remove_extern_crate::foo!();
+    }
+}
diff --git a/tests/ui/rust-2018/remove-extern-crate.rs b/tests/ui/rust-2018/remove-extern-crate.rs
index bbb84cd462d..aec0bc7c374 100644
--- a/tests/ui/rust-2018/remove-extern-crate.rs
+++ b/tests/ui/rust-2018/remove-extern-crate.rs
@@ -23,6 +23,7 @@ extern crate alloc;
 fn main() {
     another_name::mem::drop(3);
     another::foo();
+    with_visibility::foo();
     remove_extern_crate::foo!();
     bar!();
     alloc::vec![5];
@@ -37,3 +38,12 @@ mod another {
         remove_extern_crate::foo!();
     }
 }
+
+mod with_visibility {
+    pub extern crate core; //~ WARNING `extern crate` is not idiomatic
+
+    pub fn foo() {
+        core::mem::drop(4);
+        remove_extern_crate::foo!();
+    }
+}
diff --git a/tests/ui/rust-2018/remove-extern-crate.stderr b/tests/ui/rust-2018/remove-extern-crate.stderr
index bde4c180811..d07358e471b 100644
--- a/tests/ui/rust-2018/remove-extern-crate.stderr
+++ b/tests/ui/rust-2018/remove-extern-crate.stderr
@@ -12,10 +12,26 @@ LL | #![warn(rust_2018_idioms)]
    = note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]`
 
 warning: `extern crate` is not idiomatic in the new edition
-  --> $DIR/remove-extern-crate.rs:32:5
+  --> $DIR/remove-extern-crate.rs:33:5
    |
 LL |     extern crate core;
-   |     ^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+help: convert it to a `use`
+   |
+LL |     use core;
+   |     ~~~
+
+warning: `extern crate` is not idiomatic in the new edition
+  --> $DIR/remove-extern-crate.rs:43:5
+   |
+LL |     pub extern crate core;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert it to a `use`
+   |
+LL |     pub use core;
+   |         ~~~
 
-warning: 2 warnings emitted
+warning: 3 warnings emitted
 
diff --git a/tests/ui/traits/issue-77982.stderr b/tests/ui/traits/issue-77982.stderr
index a397b0accc8..d4fea05fe4b 100644
--- a/tests/ui/traits/issue-77982.stderr
+++ b/tests/ui/traits/issue-77982.stderr
@@ -43,7 +43,7 @@ LL |     let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
    |                                            |
    |                                            required by a bound introduced by this call
    |
-   = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
+   = note: multiple `impl`s satisfying `u32: From<_>` found in the `core` crate:
            - impl From<Ipv4Addr> for u32;
            - impl From<NonZeroU32> for u32;
            - impl From<bool> for u32;
diff --git a/tests/ui/traits/new-solver/try-example.rs b/tests/ui/traits/new-solver/try-example.rs
new file mode 100644
index 00000000000..e826f3a0059
--- /dev/null
+++ b/tests/ui/traits/new-solver/try-example.rs
@@ -0,0 +1,28 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+use std::error::Error;
+
+fn main() -> Result<(), Box<dyn Error>> {
+    let x: i32 = parse()?;
+    Ok(())
+}
+
+trait Parse {}
+
+impl Parse for i32 {}
+
+#[derive(Debug)]
+struct ParseError;
+
+impl std::fmt::Display for ParseError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "ParseError")
+    }
+}
+
+impl Error for ParseError {}
+
+fn parse<T: Parse>() -> Result<T, ParseError> {
+    todo!()
+}
diff --git a/tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs b/tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs
new file mode 100644
index 00000000000..019c6e81c50
--- /dev/null
+++ b/tests/ui/typeck/lazy-norm/equating-projection-cyclically.rs
@@ -0,0 +1,24 @@
+// compile-flags: -Ztrait-solver=next
+// known-bug: unknown
+
+trait Test {
+    type Assoc;
+}
+
+fn transform<T: Test>(x: T) -> T::Assoc {
+    todo!()
+}
+
+impl Test for i32 {
+    type Assoc = i32;
+}
+
+impl Test for String {
+    type Assoc = String;
+}
+
+fn main() {
+    let mut x = Default::default();
+    x = transform(x);
+    x = 1i32;
+}
diff --git a/tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr b/tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr
new file mode 100644
index 00000000000..57cbc65a17a
--- /dev/null
+++ b/tests/ui/typeck/lazy-norm/equating-projection-cyclically.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/equating-projection-cyclically.rs:22:19
+   |
+LL |     x = transform(x);
+   |                   ^ expected inferred type, found associated type
+   |
+   = note:         expected type `_`
+           found associated type `<_ as Test>::Assoc`
+   = help: consider constraining the associated type `<_ as Test>::Assoc` to `_`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.