about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-11-15 06:43:28 +0000
committerbors <bors@rust-lang.org>2022-11-15 06:43:28 +0000
commitca92d90b5917e7176d5ff06607a2cd5352c088d3 (patch)
treeb34e3c368642c150f3c81bc98d45d57353480bbc /src
parent101e1822c3e54e63996c8aaa014d55716f3937eb (diff)
parent7c7cb7182f8b2211005d3f82126e5f45e270ad21 (diff)
downloadrust-ca92d90b5917e7176d5ff06607a2cd5352c088d3.tar.gz
rust-ca92d90b5917e7176d5ff06607a2cd5352c088d3.zip
Auto merge of #104428 - matthiaskrgr:rollup-jo3078i, r=matthiaskrgr
Rollup of 13 pull requests

Successful merges:

 - #103842 (Adding Fuchsia compiler testing script, docs)
 - #104354 (Remove leading newlines from `NonZero*` doc examples)
 - #104372 (Update compiler-builtins)
 - #104380 (rustdoc: remove unused CSS `code { opacity: 1 }`)
 - #104381 (Remove dead NoneError diagnostic handling)
 - #104383 (Remove unused symbols and diagnostic items)
 - #104391 (Deriving cleanups)
 - #104403 (Specify language of code comment to generate document)
 - #104404 (Fix missing minification for static files)
 - #104413 ([llvm-wrapper] adapt for LLVM API change)
 - #104415 (rustdoc: fix corner case in search keyboard commands)
 - #104422 (Fix suggest associated call syntax)
 - #104426 (Add test for #102154)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'src')
-rw-r--r--src/ci/docker/scripts/fuchsia-test-runner.py1041
-rw-r--r--src/doc/rustc/src/platform-support/fuchsia.md56
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css4
-rw-r--r--src/librustdoc/html/static/js/search.js1
-rw-r--r--src/librustdoc/html/static_files.rs8
-rw-r--r--src/test/rustdoc-gui/search-keyboard.goml28
-rw-r--r--src/test/rustdoc/issue-102154.rs13
-rw-r--r--src/test/ui/suggestions/dont-suggest-ufcs-for-const.rs4
-rw-r--r--src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr15
-rw-r--r--src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed15
-rw-r--r--src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs15
-rw-r--r--src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr19
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs12
13 files changed, 1217 insertions, 14 deletions
diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py
new file mode 100644
index 00000000000..a2708d16947
--- /dev/null
+++ b/src/ci/docker/scripts/fuchsia-test-runner.py
@@ -0,0 +1,1041 @@
+#!/usr/bin/env python3
+
+"""
+The Rust toolchain test runner for Fuchsia.
+
+For instructions on running the compiler test suite, see
+https://doc.rust-lang.org/stable/rustc/platform-support/fuchsia.html#aarch64-fuchsia-and-x86_64-fuchsia
+"""
+
+import argparse
+from dataclasses import dataclass
+import glob
+import hashlib
+import json
+import os
+import platform
+import re
+import shutil
+import signal
+import subprocess
+import sys
+from typing import ClassVar, List
+
+
+@dataclass
+class TestEnvironment:
+    rust_dir: str
+    sdk_dir: str
+    target_arch: str
+    package_server_pid: int = None
+    emu_addr: str = None
+    libstd_name: str = None
+    libtest_name: str = None
+    verbose: bool = False
+
+    @staticmethod
+    def tmp_dir():
+        tmp_dir = os.environ.get("TEST_TOOLCHAIN_TMP_DIR")
+        if tmp_dir is not None:
+            return os.path.abspath(tmp_dir)
+        return os.path.join(os.path.dirname(__file__), "tmp~")
+
+    @classmethod
+    def env_file_path(cls):
+        return os.path.join(cls.tmp_dir(), "test_env.json")
+
+    @classmethod
+    def from_args(cls, args):
+        return cls(
+            os.path.abspath(args.rust),
+            os.path.abspath(args.sdk),
+            args.target_arch,
+            verbose=args.verbose,
+        )
+
+    @classmethod
+    def read_from_file(cls):
+        with open(cls.env_file_path(), encoding="utf-8") as f:
+            test_env = json.loads(f.read())
+            return cls(
+                test_env["rust_dir"],
+                test_env["sdk_dir"],
+                test_env["target_arch"],
+                libstd_name=test_env["libstd_name"],
+                libtest_name=test_env["libtest_name"],
+                emu_addr=test_env["emu_addr"],
+                package_server_pid=test_env["package_server_pid"],
+                verbose=test_env["verbose"],
+            )
+
+    def image_name(self):
+        if self.target_arch == "x64":
+            return "qemu-x64"
+        if self.target_arch == "arm64":
+            return "qemu-arm64"
+        raise Exception(f"Unrecognized target architecture {self.target_arch}")
+
+    def write_to_file(self):
+        with open(self.env_file_path(), "w", encoding="utf-8") as f:
+            f.write(json.dumps(self.__dict__))
+
+    def ssh_dir(self):
+        return os.path.join(self.tmp_dir(), "ssh")
+
+    def ssh_keyfile_path(self):
+        return os.path.join(self.ssh_dir(), "fuchsia_ed25519")
+
+    def ssh_authfile_path(self):
+        return os.path.join(self.ssh_dir(), "fuchsia_authorized_keys")
+
+    def vdl_output_path(self):
+        return os.path.join(self.tmp_dir(), "vdl_output")
+
+    def package_server_log_path(self):
+        return os.path.join(self.tmp_dir(), "package_server_log")
+
+    def emulator_log_path(self):
+        return os.path.join(self.tmp_dir(), "emulator_log")
+
+    def packages_dir(self):
+        return os.path.join(self.tmp_dir(), "packages")
+
+    def output_dir(self):
+        return os.path.join(self.tmp_dir(), "output")
+
+    TEST_REPO_NAME: ClassVar[str] = "rust-testing"
+
+    def repo_dir(self):
+        return os.path.join(self.tmp_dir(), self.TEST_REPO_NAME)
+
+    def rustlib_dir(self):
+        if self.target_arch == "x64":
+            return "x86_64-fuchsia"
+        if self.target_arch == "arm64":
+            return "aarch64-fuchsia"
+        raise Exception(f"Unrecognized target architecture {self.target_arch}")
+
+    def libs_dir(self):
+        return os.path.join(
+            self.rust_dir,
+            "lib",
+        )
+
+    def rustlibs_dir(self):
+        return os.path.join(
+            self.libs_dir(),
+            "rustlib",
+            self.rustlib_dir(),
+            "lib",
+        )
+
+    def sdk_arch(self):
+        machine = platform.machine()
+        if machine == "x86_64":
+            return "x64"
+        if machine == "arm":
+            return "a64"
+        raise Exception(f"Unrecognized host architecture {machine}")
+
+    def tool_path(self, tool):
+        return os.path.join(self.sdk_dir, "tools", self.sdk_arch(), tool)
+
+    def host_arch_triple(self):
+        machine = platform.machine()
+        if machine == "x86_64":
+            return "x86_64-unknown-linux-gnu"
+        if machine == "arm":
+            return "aarch64-unknown-linux-gnu"
+        raise Exception(f"Unrecognized host architecture {machine}")
+
+    def zxdb_script_path(self):
+        return os.path.join(self.tmp_dir(), "zxdb_script")
+
+    def log_info(self, msg):
+        print(msg)
+
+    def log_debug(self, msg):
+        if self.verbose:
+            print(msg)
+
+    def subprocess_output(self):
+        if self.verbose:
+            return sys.stdout
+        return subprocess.DEVNULL
+
+    def ffx_daemon_log_path(self):
+        return os.path.join(self.tmp_dir(), "ffx_daemon_log")
+
+    def ffx_isolate_dir(self):
+        return os.path.join(self.tmp_dir(), "ffx_isolate")
+
+    def ffx_home_dir(self):
+        return os.path.join(self.ffx_isolate_dir(), "user-home")
+
+    def ffx_tmp_dir(self):
+        return os.path.join(self.ffx_isolate_dir(), "tmp")
+
+    def ffx_log_dir(self):
+        return os.path.join(self.ffx_isolate_dir(), "log")
+
+    def ffx_user_config_dir(self):
+        return os.path.join(self.ffx_xdg_config_home(), "Fuchsia", "ffx", "config")
+
+    def ffx_user_config_path(self):
+        return os.path.join(self.ffx_user_config_dir(), "config.json")
+
+    def ffx_xdg_config_home(self):
+        if platform.system() == "Darwin":
+            return os.path.join(self.ffx_home_dir(), "Library", "Preferences")
+        return os.path.join(self.ffx_home_dir(), ".local", "share")
+
+    def ffx_ascendd_path(self):
+        return os.path.join(self.ffx_tmp_dir(), "ascendd")
+
+    def start_ffx_isolation(self):
+        # Most of this is translated directly from ffx's isolate library
+        os.mkdir(self.ffx_isolate_dir())
+        os.mkdir(self.ffx_home_dir())
+        os.mkdir(self.ffx_tmp_dir())
+        os.mkdir(self.ffx_log_dir())
+
+        fuchsia_dir = os.path.join(self.ffx_home_dir(), ".fuchsia")
+        os.mkdir(fuchsia_dir)
+
+        fuchsia_debug_dir = os.path.join(fuchsia_dir, "debug")
+        os.mkdir(fuchsia_debug_dir)
+
+        metrics_dir = os.path.join(fuchsia_dir, "metrics")
+        os.mkdir(metrics_dir)
+
+        analytics_path = os.path.join(metrics_dir, "analytics-status")
+        with open(analytics_path, "w", encoding="utf-8") as analytics_file:
+            print("0", file=analytics_file)
+
+        ffx_path = os.path.join(metrics_dir, "ffx")
+        with open(ffx_path, "w", encoding="utf-8") as ffx_file:
+            print("1", file=ffx_file)
+
+        os.makedirs(self.ffx_user_config_dir())
+
+        with open(
+            self.ffx_user_config_path(), "w", encoding="utf-8"
+        ) as config_json_file:
+            user_config_for_test = {
+                "log": {
+                    "enabled": True,
+                    "dir": self.ffx_log_dir(),
+                },
+                "overnet": {
+                    "socket": self.ffx_ascendd_path(),
+                },
+                "ssh": {
+                    "pub": self.ssh_authfile_path(),
+                    "priv": self.ssh_keyfile_path(),
+                },
+                "test": {
+                    "is_isolated": True,
+                    "experimental_structured_output": True,
+                },
+            }
+            print(json.dumps(user_config_for_test), file=config_json_file)
+
+        ffx_env_path = os.path.join(self.ffx_user_config_dir(), ".ffx_env")
+        with open(ffx_env_path, "w", encoding="utf-8") as ffx_env_file:
+            ffx_env_config_for_test = {
+                "user": self.ffx_user_config_path(),
+                "build": None,
+                "global": None,
+            }
+            print(json.dumps(ffx_env_config_for_test), file=ffx_env_file)
+
+        # Start ffx daemon
+        # We want this to be a long-running process that persists after the script finishes
+        # pylint: disable=consider-using-with
+        with open(
+            self.ffx_daemon_log_path(), "w", encoding="utf-8"
+        ) as ffx_daemon_log_file:
+            subprocess.Popen(
+                [
+                    self.tool_path("ffx"),
+                    "--config",
+                    self.ffx_user_config_path(),
+                    "daemon",
+                    "start",
+                ],
+                env=self.ffx_cmd_env(),
+                stdout=ffx_daemon_log_file,
+                stderr=ffx_daemon_log_file,
+            )
+
+    def ffx_cmd_env(self):
+        result = {
+            "HOME": self.ffx_home_dir(),
+            "XDG_CONFIG_HOME": self.ffx_xdg_config_home(),
+            "ASCENDD": self.ffx_ascendd_path(),
+            "FUCHSIA_SSH_KEY": self.ssh_keyfile_path(),
+            # We want to use our own specified temp directory
+            "TMP": self.tmp_dir(),
+            "TEMP": self.tmp_dir(),
+            "TMPDIR": self.tmp_dir(),
+            "TEMPDIR": self.tmp_dir(),
+        }
+
+        return result
+
+    def stop_ffx_isolation(self):
+        subprocess.check_call(
+            [
+                self.tool_path("ffx"),
+                "--config",
+                self.ffx_user_config_path(),
+                "daemon",
+                "stop",
+            ],
+            env=self.ffx_cmd_env(),
+            stdout=self.subprocess_output(),
+            stderr=self.subprocess_output(),
+        )
+
+    def start(self):
+        """Sets up the testing environment and prepares to run tests.
+
+        Args:
+            args: The command-line arguments to this command.
+
+        During setup, this function will:
+        - Locate necessary shared libraries
+        - Create a new temp directory (this is where all temporary files are stored)
+        - Start an emulator
+        - Start an update server
+        - Create a new package repo and register it with the emulator
+        - Write test environment settings to a temporary file
+        """
+
+        # Initialize temp directory
+        if not os.path.exists(self.tmp_dir()):
+            os.mkdir(self.tmp_dir())
+        elif len(os.listdir(self.tmp_dir())) != 0:
+            raise Exception(f"Temp directory is not clean (in {self.tmp_dir()})")
+
+        os.mkdir(self.ssh_dir())
+        os.mkdir(self.output_dir())
+
+        # Find libstd and libtest
+        libstd_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libstd-*.so"))
+        libtest_paths = glob.glob(os.path.join(self.rustlibs_dir(), "libtest-*.so"))
+
+        if not libstd_paths:
+            raise Exception(f"Failed to locate libstd (in {self.rustlibs_dir()})")
+
+        if not libtest_paths:
+            raise Exception(f"Failed to locate libtest (in {self.rustlibs_dir()})")
+
+        self.libstd_name = os.path.basename(libstd_paths[0])
+        self.libtest_name = os.path.basename(libtest_paths[0])
+
+        # Generate SSH keys for the emulator to use
+        self.log_info("Generating SSH keys...")
+        subprocess.check_call(
+            [
+                "ssh-keygen",
+                "-N",
+                "",
+                "-t",
+                "ed25519",
+                "-f",
+                self.ssh_keyfile_path(),
+                "-C",
+                "Generated by test_toolchain.py",
+            ],
+            stdout=self.subprocess_output(),
+            stderr=self.subprocess_output(),
+        )
+        authfile_contents = subprocess.check_output(
+            [
+                "ssh-keygen",
+                "-y",
+                "-f",
+                self.ssh_keyfile_path(),
+            ],
+            stderr=self.subprocess_output(),
+        )
+        with open(self.ssh_authfile_path(), "wb") as authfile:
+            authfile.write(authfile_contents)
+
+        # Start ffx isolation
+        self.log_info("Starting ffx isolation...")
+        self.start_ffx_isolation()
+
+        # Start emulator (this will generate the vdl output)
+        self.log_info("Starting emulator...")
+        subprocess.check_call(
+            [
+                self.tool_path("fvdl"),
+                "--sdk",
+                "start",
+                "--tuntap",
+                "--headless",
+                "--nointeractive",
+                "--ssh",
+                self.ssh_dir(),
+                "--vdl-output",
+                self.vdl_output_path(),
+                "--emulator-log",
+                self.emulator_log_path(),
+                "--image-name",
+                self.image_name(),
+            ],
+            stdout=self.subprocess_output(),
+            stderr=self.subprocess_output(),
+        )
+
+        # Parse vdl output for relevant information
+        with open(self.vdl_output_path(), encoding="utf-8") as f:
+            vdl_content = f.read()
+            matches = re.search(
+                r'network_address:\s+"\[([0-9a-f]{1,4}:(:[0-9a-f]{1,4}){4}%qemu)\]"',
+                vdl_content,
+            )
+            self.emu_addr = matches.group(1)
+
+        # Create new package repo
+        self.log_info("Creating package repo...")
+        subprocess.check_call(
+            [
+                self.tool_path("pm"),
+                "newrepo",
+                "-repo",
+                self.repo_dir(),
+            ],
+            stdout=self.subprocess_output(),
+            stderr=self.subprocess_output(),
+        )
+
+        # Start package server
+        self.log_info("Starting package server...")
+        with open(
+            self.package_server_log_path(), "w", encoding="utf-8"
+        ) as package_server_log:
+            # We want this to be a long-running process that persists after the script finishes
+            # pylint: disable=consider-using-with
+            self.package_server_pid = subprocess.Popen(
+                [
+                    self.tool_path("pm"),
+                    "serve",
+                    "-vt",
+                    "-repo",
+                    self.repo_dir(),
+                    "-l",
+                    ":8084",
+                ],
+                stdout=package_server_log,
+                stderr=package_server_log,
+            ).pid
+
+        # Register package server with emulator
+        self.log_info("Registering package server...")
+        ssh_client = subprocess.check_output(
+            [
+                "ssh",
+                "-i",
+                self.ssh_keyfile_path(),
+                "-o",
+                "StrictHostKeyChecking=accept-new",
+                self.emu_addr,
+                "-f",
+                "echo $SSH_CLIENT",
+            ],
+            text=True,
+        )
+        repo_addr = ssh_client.split()[0].replace("%", "%25")
+        repo_url = f"http://[{repo_addr}]:8084/config.json"
+        subprocess.check_call(
+            [
+                "ssh",
+                "-i",
+                self.ssh_keyfile_path(),
+                "-o",
+                "StrictHostKeyChecking=accept-new",
+                self.emu_addr,
+                "-f",
+                f"pkgctl repo add url -f 1 -n {self.TEST_REPO_NAME} {repo_url}",
+            ],
+            stdout=self.subprocess_output(),
+            stderr=self.subprocess_output(),
+        )
+
+        # Write to file
+        self.write_to_file()
+
+        self.log_info("Success! Your environment is ready to run tests.")
+
+    # FIXME: shardify this
+    # `facet` statement required for TCP testing via
+    # protocol `fuchsia.posix.socket.Provider`. See
+    # https://fuchsia.dev/fuchsia-src/development/testing/components/test_runner_framework?hl=en#legacy_non-hermetic_tests
+    CML_TEMPLATE: ClassVar[
+        str
+    ] = """
+    {{
+        program: {{
+            runner: "elf_test_runner",
+            binary: "bin/{exe_name}",
+            forward_stderr_to: "log",
+            forward_stdout_to: "log",
+            environ: [{env_vars}
+            ]
+        }},
+        capabilities: [
+            {{ protocol: "fuchsia.test.Suite" }},
+        ],
+        expose: [
+            {{
+                protocol: "fuchsia.test.Suite",
+                from: "self",
+            }},
+        ],
+        use: [
+            {{ storage: "data", path: "/data" }},
+            {{ protocol: [ "fuchsia.process.Launcher" ] }},
+            {{ protocol: [ "fuchsia.posix.socket.Provider" ] }}
+        ],
+        facets: {{
+            "fuchsia.test": {{ type: "system" }},
+        }},
+    }}
+    """
+
+    MANIFEST_TEMPLATE = """
+    meta/package={package_dir}/meta/package
+    meta/{package_name}.cm={package_dir}/meta/{package_name}.cm
+    bin/{exe_name}={bin_path}
+    lib/{libstd_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libstd_name}
+    lib/{libtest_name}={rust_dir}/lib/rustlib/{rustlib_dir}/lib/{libtest_name}
+    lib/ld.so.1={sdk_dir}/arch/{target_arch}/sysroot/lib/libc.so
+    lib/libzircon.so={sdk_dir}/arch/{target_arch}/sysroot/lib/libzircon.so
+    lib/libfdio.so={sdk_dir}/arch/{target_arch}/lib/libfdio.so
+    """
+
+    TEST_ENV_VARS: ClassVar[List[str]] = [
+        "TEST_EXEC_ENV",
+        "RUST_MIN_STACK",
+        "RUST_BACKTRACE",
+        "RUST_NEWRT",
+        "RUST_LOG",
+        "RUST_TEST_THREADS",
+    ]
+
+    def run(self, args):
+        """Runs the requested test in the testing environment.
+
+        Args:
+        args: The command-line arguments to this command.
+        Returns:
+        The return code of the test (0 for success, else failure).
+
+        To run a test, this function will:
+        - Create, compile, archive, and publish a test package
+        - Run the test package on the emulator
+        - Forward the test's stdout and stderr as this script's stdout and stderr
+        """
+
+        bin_path = os.path.abspath(args.bin_path)
+
+        # Build a unique, deterministic name for the test using the name of the
+        # binary and the last 6 hex digits of the hash of the full path
+        def path_checksum(path):
+            m = hashlib.sha256()
+            m.update(path.encode("utf-8"))
+            return m.hexdigest()[0:6]
+
+        base_name = os.path.basename(os.path.dirname(args.bin_path))
+        exe_name = base_name.lower().replace(".", "_")
+        package_name = f"{exe_name}_{path_checksum(bin_path)}"
+
+        package_dir = os.path.join(self.packages_dir(), package_name)
+        cml_path = os.path.join(package_dir, "meta", f"{package_name}.cml")
+        cm_path = os.path.join(package_dir, "meta", f"{package_name}.cm")
+        manifest_path = os.path.join(package_dir, f"{package_name}.manifest")
+        far_path = os.path.join(package_dir, f"{package_name}-0.far")
+
+        shared_libs = args.shared_libs[: args.n]
+        arguments = args.shared_libs[args.n :]
+
+        test_output_dir = os.path.join(self.output_dir(), package_name)
+
+        # Clean and create temporary output directory
+        if os.path.exists(test_output_dir):
+            shutil.rmtree(test_output_dir)
+
+        os.mkdir(test_output_dir)
+
+        # Open log file
+        log_path = os.path.join(test_output_dir, "log")
+        with open(log_path, "w", encoding="utf-8") as log_file:
+
+            def log(msg):
+                print(msg, file=log_file)
+                log_file.flush()
+
+            log(f"Bin path: {bin_path}")
+
+            log("Setting up package...")
+
+            # Set up package
+            subprocess.check_call(
+                [
+                    self.tool_path("pm"),
+                    "-o",
+                    package_dir,
+                    "-n",
+                    package_name,
+                    "init",
+                ],
+                stdout=log_file,
+                stderr=log_file,
+            )
+
+            log("Writing CML...")
+
+            # Write and compile CML
+            with open(cml_path, "w", encoding="utf-8") as cml:
+                # Collect environment variables
+                env_vars = ""
+                for var_name in self.TEST_ENV_VARS:
+                    var_value = os.getenv(var_name)
+                    if var_value is not None:
+                        env_vars += f'\n            "{var_name}={var_value}",'
+
+                # Default to no backtrace for test suite
+                if os.getenv("RUST_BACKTRACE") == None:
+                    env_vars += f'\n            "RUST_BACKTRACE=0",'
+
+                cml.write(
+                    self.CML_TEMPLATE.format(env_vars=env_vars, exe_name=exe_name)
+                )
+
+            log("Compiling CML...")
+
+            subprocess.check_call(
+                [
+                    self.tool_path("cmc"),
+                    "compile",
+                    cml_path,
+                    "--includepath",
+                    ".",
+                    "--output",
+                    cm_path,
+                ],
+                stdout=log_file,
+                stderr=log_file,
+            )
+
+            log("Writing manifest...")
+
+            # Write, build, and archive manifest
+            with open(manifest_path, "w", encoding="utf-8") as manifest:
+                manifest.write(
+                    self.MANIFEST_TEMPLATE.format(
+                        bin_path=bin_path,
+                        exe_name=exe_name,
+                        package_dir=package_dir,
+                        package_name=package_name,
+                        rust_dir=self.rust_dir,
+                        rustlib_dir=self.rustlib_dir(),
+                        sdk_dir=self.sdk_dir,
+                        libstd_name=self.libstd_name,
+                        libtest_name=self.libtest_name,
+                        target_arch=self.target_arch,
+                    )
+                )
+                for shared_lib in shared_libs:
+                    manifest.write(f"lib/{os.path.basename(shared_lib)}={shared_lib}\n")
+
+            log("Compiling and archiving manifest...")
+
+            subprocess.check_call(
+                [
+                    self.tool_path("pm"),
+                    "-o",
+                    package_dir,
+                    "-m",
+                    manifest_path,
+                    "build",
+                ],
+                stdout=log_file,
+                stderr=log_file,
+            )
+            subprocess.check_call(
+                [
+                    self.tool_path("pm"),
+                    "-o",
+                    package_dir,
+                    "-m",
+                    manifest_path,
+                    "archive",
+                ],
+                stdout=log_file,
+                stderr=log_file,
+            )
+
+            log("Publishing package to repo...")
+
+            # Publish package to repo
+            subprocess.check_call(
+                [
+                    self.tool_path("pm"),
+                    "publish",
+                    "-a",
+                    "-repo",
+                    self.repo_dir(),
+                    "-f",
+                    far_path,
+                ],
+                stdout=log_file,
+                stderr=log_file,
+            )
+
+            log("Running ffx test...")
+
+            # Run test on emulator
+            subprocess.run(
+                [
+                    self.tool_path("ffx"),
+                    "--config",
+                    self.ffx_user_config_path(),
+                    "test",
+                    "run",
+                    f"fuchsia-pkg://{self.TEST_REPO_NAME}/{package_name}#meta/{package_name}.cm",
+                    "--min-severity-logs",
+                    "TRACE",
+                    "--output-directory",
+                    test_output_dir,
+                    "--",
+                ]
+                + arguments,
+                env=self.ffx_cmd_env(),
+                check=False,
+                stdout=log_file,
+                stderr=log_file,
+            )
+
+            log("Reporting test suite output...")
+
+            # Read test suite output
+            run_summary_path = os.path.join(test_output_dir, "run_summary.json")
+            if os.path.exists(run_summary_path):
+                with open(run_summary_path, encoding="utf-8") as f:
+                    run_summary = json.loads(f.read())
+
+                suite = run_summary["data"]["suites"][0]
+                case = suite["cases"][0]
+
+                return_code = 0 if case["outcome"] == "PASSED" else 1
+
+                artifacts = case["artifacts"]
+                artifact_dir = case["artifact_dir"]
+                stdout_path = None
+                stderr_path = None
+
+                for path, artifact in artifacts.items():
+                    artifact_path = os.path.join(test_output_dir, artifact_dir, path)
+                    artifact_type = artifact["artifact_type"]
+
+                    if artifact_type == "STDERR":
+                        stderr_path = artifact_path
+                    elif artifact_type == "STDOUT":
+                        stdout_path = artifact_path
+
+                if stdout_path is not None and os.path.exists(stdout_path):
+                    with open(stdout_path, encoding="utf-8") as f:
+                        print(f.read(), file=sys.stdout, end="")
+
+                if stderr_path is not None and os.path.exists(stderr_path):
+                    with open(stderr_path, encoding="utf-8") as f:
+                        print(f.read(), file=sys.stderr, end="")
+            else:
+                log("Failed to open test run summary")
+                return_code = 254
+
+            log("Done!")
+
+        return return_code
+
+    def stop(self):
+        """Shuts down and cleans up the testing environment.
+
+        Args:
+        args: The command-line arguments to this command.
+        Returns:
+        The return code of the test (0 for success, else failure).
+
+        During cleanup, this function will stop the emulator, package server, and
+        update server, then delete all temporary files. If an error is encountered
+        while stopping any running processes, the temporary files will not be deleted.
+        Passing --delete-tmp will force the process to delete the files anyway.
+        """
+
+        self.log_debug("Reporting logs...")
+
+        # Print test log files
+        for test_dir in os.listdir(self.output_dir()):
+            log_path = os.path.join(self.output_dir(), test_dir, "log")
+            self.log_debug(f"\n---- Logs for test '{test_dir}' ----\n")
+            if os.path.exists(log_path):
+                with open(log_path, encoding="utf-8") as log:
+                    self.log_debug(log.read())
+            else:
+                self.log_debug("No logs found")
+
+        # Print the emulator log
+        self.log_debug("\n---- Emulator logs ----\n")
+        if os.path.exists(self.emulator_log_path()):
+            with open(self.emulator_log_path(), encoding="utf-8") as log:
+                self.log_debug(log.read())
+        else:
+            self.log_debug("No emulator logs found")
+
+        # Print the package server log
+        self.log_debug("\n---- Package server log ----\n")
+        if os.path.exists(self.package_server_log_path()):
+            with open(self.package_server_log_path(), encoding="utf-8") as log:
+                self.log_debug(log.read())
+        else:
+            self.log_debug("No package server log found")
+
+        # Print the ffx daemon log
+        self.log_debug("\n---- ffx daemon log ----\n")
+        if os.path.exists(self.ffx_daemon_log_path()):
+            with open(self.ffx_daemon_log_path(), encoding="utf-8") as log:
+                self.log_debug(log.read())
+        else:
+            self.log_debug("No ffx daemon log found")
+
+        # Stop package server
+        self.log_info("Stopping package server...")
+        os.kill(self.package_server_pid, signal.SIGTERM)
+
+        # Shut down the emulator
+        self.log_info("Stopping emulator...")
+        subprocess.check_call(
+            [
+                self.tool_path("fvdl"),
+                "--sdk",
+                "kill",
+                "--launched-proto",
+                self.vdl_output_path(),
+            ],
+            stdout=self.subprocess_output(),
+            stderr=self.subprocess_output(),
+        )
+
+        # Stop ffx isolation
+        self.log_info("Stopping ffx isolation...")
+        self.stop_ffx_isolation()
+
+    def delete_tmp(self):
+        # Remove temporary files
+        self.log_info("Deleting temporary files...")
+        shutil.rmtree(self.tmp_dir(), ignore_errors=True)
+
+    def debug(self, args):
+        command = [
+            self.tool_path("ffx"),
+            "--config",
+            self.ffx_user_config_path(),
+            "debug",
+            "connect",
+            "--",
+            "--build-id-dir",
+            os.path.join(self.sdk_dir, ".build-id"),
+            "--build-id-dir",
+            os.path.join(self.libs_dir(), ".build-id"),
+        ]
+
+        # Add rust source if it's available
+        if args.rust_src is not None:
+            command += [
+                "--build-dir",
+                args.rust_src,
+            ]
+
+        # Add fuchsia source if it's available
+        if args.fuchsia_src is not None:
+            command += [
+                "--build-dir",
+                os.path.join(args.fuchsia_src, "out", "default"),
+            ]
+
+        # Load debug symbols for the test binary and automatically attach
+        if args.test is not None:
+            if args.rust_src is None:
+                raise Exception(
+                    "A Rust source path is required with the `test` argument"
+                )
+
+            test_name = os.path.splitext(os.path.basename(args.test))[0]
+
+            build_dir = os.path.join(
+                args.rust_src,
+                "fuchsia-build",
+                self.host_arch_triple(),
+            )
+            test_dir = os.path.join(
+                build_dir,
+                "test",
+                os.path.dirname(args.test),
+                test_name,
+            )
+
+            with open(self.zxdb_script_path(), mode="w", encoding="utf-8") as f:
+                print(f"attach {test_name[:31]}", file=f)
+
+            command += [
+                "--symbol-path",
+                test_dir,
+                "-S",
+                self.zxdb_script_path(),
+            ]
+
+        # Add any other zxdb arguments the user passed
+        if args.zxdb_args is not None:
+            command += args.zxdb_args
+
+        # Connect to the running emulator with zxdb
+        subprocess.run(command, env=self.ffx_cmd_env(), check=False)
+
+
+def start(args):
+    test_env = TestEnvironment.from_args(args)
+    test_env.start()
+    return 0
+
+
+def run(args):
+    test_env = TestEnvironment.read_from_file()
+    return test_env.run(args)
+
+
+def stop(args):
+    test_env = TestEnvironment.read_from_file()
+    test_env.stop()
+    if not args.no_delete:
+        test_env.delete_tmp()
+    return 0
+
+
+def delete_tmp(args):
+    del args
+    test_env = TestEnvironment.read_from_file()
+    test_env.delete_tmp()
+    return 0
+
+
+def debug(args):
+    test_env = TestEnvironment.read_from_file()
+    test_env.debug(args)
+    return 0
+
+
+def main():
+    parser = argparse.ArgumentParser()
+
+    def print_help(args):
+        del args
+        parser.print_help()
+        return 0
+
+    parser.set_defaults(func=print_help)
+
+    subparsers = parser.add_subparsers(help="valid sub-commands")
+
+    start_parser = subparsers.add_parser(
+        "start", help="initializes the testing environment"
+    )
+    start_parser.add_argument(
+        "--rust",
+        help="the directory of the installed Rust compiler for Fuchsia",
+        required=True,
+    )
+    start_parser.add_argument(
+        "--sdk",
+        help="the directory of the fuchsia SDK",
+        required=True,
+    )
+    start_parser.add_argument(
+        "--verbose",
+        help="prints more output from executed processes",
+        action="store_true",
+    )
+    start_parser.add_argument(
+        "--target-arch",
+        help="the architecture of the image to test",
+        required=True,
+    )
+    start_parser.set_defaults(func=start)
+
+    run_parser = subparsers.add_parser(
+        "run", help="run a test in the testing environment"
+    )
+    run_parser.add_argument(
+        "n", help="the number of shared libs passed along with the executable", type=int
+    )
+    run_parser.add_argument("bin_path", help="path to the binary to run")
+    run_parser.add_argument(
+        "shared_libs",
+        help="the shared libs passed along with the binary",
+        nargs=argparse.REMAINDER,
+    )
+    run_parser.set_defaults(func=run)
+
+    stop_parser = subparsers.add_parser(
+        "stop", help="shuts down and cleans up the testing environment"
+    )
+    stop_parser.add_argument(
+        "--no-delete",
+        default=False,
+        action="store_true",
+        help="don't delete temporary files after stopping",
+    )
+    stop_parser.set_defaults(func=stop)
+
+    delete_parser = subparsers.add_parser(
+        "delete-tmp",
+        help="deletes temporary files after the testing environment has been manually cleaned up",
+    )
+    delete_parser.set_defaults(func=delete_tmp)
+
+    debug_parser = subparsers.add_parser(
+        "debug",
+        help="connect to the active testing environment with zxdb",
+    )
+    debug_parser.add_argument(
+        "--rust-src",
+        default=None,
+        help="the path to the Rust source being tested",
+    )
+    debug_parser.add_argument(
+        "--fuchsia-src",
+        default=None,
+        help="the path to the Fuchsia source",
+    )
+    debug_parser.add_argument(
+        "--test",
+        default=None,
+        help="the path to the test to debug (e.g. ui/box/new.rs)",
+    )
+    debug_parser.add_argument(
+        "zxdb_args",
+        default=None,
+        nargs=argparse.REMAINDER,
+        help="any additional arguments to pass to zxdb",
+    )
+    debug_parser.set_defaults(func=debug)
+
+    args = parser.parse_args()
+    return args.func(args)
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 1ff6003c121..62cad19d0ec 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -641,8 +641,60 @@ available on the [Fuchsia devsite].
 
 ### Running the compiler test suite
 
-Running the Rust test suite on Fuchsia is [not currently supported], but work is
-underway to enable it.
+Pre-requisites for running the Rust test suite on Fuchsia are:
+1. Checkout of Rust source.
+1. Setup of `config-env.sh` and `config.toml` from "[Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source)".
+1. Download of the Fuchsia SDK. Minimum supported SDK version is [9.20220726.1.1](https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:9.20220726.1.1)
+
+Interfacing with the Fuchsia emulator is handled by our test runner script located
+at `${RUST_SRC_PATH}/src/ci/docker/scripts/fuchsia-test-runner.py`.
+
+We start by activating our Fuchsia test environment. From a terminal:
+
+**Issue command from ${RUST_SRC_PATH}**
+```sh
+src/ci/docker/scripts/fuchsia-test-runner.py start
+    --rust .
+    --sdk ${SDK_PATH}
+    --target-arch {x64,arm64}
+```
+
+Next, for ease of commands, we copy `config-env.sh` and `config.toml` into our Rust source
+code path, `${RUST_SRC_PATH}`.
+
+From there, we utilize `x.py` to run our tests, using the test runner script to
+run the tests on our emulator. To run the full `src/test/ui` test suite:
+
+**Run from ${RUST_SRC_PATH}**
+```sh
+( \
+    source config-env.sh &&                                                   \
+    ./x.py                                                                    \
+    --config config.toml                                                      \
+    --stage=2                                                                 \
+    test src/test/ui                                                          \
+    --target x86_64-fuchsia                                                   \
+    --run=always --jobs 1                                                     \
+    --test-args --target-rustcflags -L                                        \
+    --test-args --target-rustcflags ${SDK_PATH}/arch/{x64|arm64}/sysroot/lib  \
+    --test-args --target-rustcflags -L                                        \
+    --test-args --target-rustcflags ${SDK_PATH}/arch/{x64|arm64}/lib          \
+    --test-args --target-rustcflags -Cpanic=abort                             \
+    --test-args --target-rustcflags -Zpanic_abort_tests                       \
+    --test-args --remote-test-client                                          \
+    --test-args src/ci/docker/scripts/fuchsia-test-runner.py                  \
+)
+```
+
+*Note: The test suite cannot be run in parallel at the moment, so `x.py`
+must be run with `--jobs 1` to ensure only one test runs at a time.*
+
+When finished, stop the test environment:
+
+**Issue command from ${RUST_SRC_PATH}**
+```sh
+src/ci/docker/scripts/fuchsia-test-runner.py stop
+```
 
 ## Debugging
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 3f295b96dc5..d195c9cf6f9 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1262,10 +1262,6 @@ h3.variant {
 	margin-left: 24px;
 }
 
-:target > code, :target > .code-header {
-	opacity: 1;
-}
-
 :target {
 	padding-right: 3px;
 	background-color: var(--target-background-color);
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index dd0531c5e70..4999bb35994 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1491,6 +1491,7 @@ function initSearch(rawSearchIndex) {
         const target = searchState.focusedByTab[searchState.currentTab] ||
             document.querySelectorAll(".search-results.active a").item(0) ||
             document.querySelectorAll("#titles > button").item(searchState.currentTab);
+        searchState.focusedByTab[searchState.currentTab] = null;
         if (target) {
             target.focus();
         }
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index afe920b7fa1..b4d4150cddb 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -19,9 +19,13 @@ impl StaticFile {
     }
 
     pub(crate) fn minified(&self) -> Vec<u8> {
-        if self.filename.ends_with(".css") {
+        let extension = match self.filename.extension() {
+            Some(e) => e,
+            None => return self.bytes.to_owned(),
+        };
+        if extension == "css" {
             minifier::css::minify(str::from_utf8(self.bytes).unwrap()).unwrap().to_string().into()
-        } else if self.filename.ends_with(".js") {
+        } else if extension == "js" {
             minifier::js::minify(str::from_utf8(self.bytes).unwrap()).to_string().into()
         } else {
             self.bytes.to_owned()
diff --git a/src/test/rustdoc-gui/search-keyboard.goml b/src/test/rustdoc-gui/search-keyboard.goml
new file mode 100644
index 00000000000..be642fc4997
--- /dev/null
+++ b/src/test/rustdoc-gui/search-keyboard.goml
@@ -0,0 +1,28 @@
+// Checks that the search tab results work correctly with function signature syntax
+// First, try a search-by-name
+goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
+write: (".search-input", "Foo")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#titles"
+
+// Now use the keyboard commands to switch to the third result.
+press-key: "ArrowDown"
+press-key: "ArrowDown"
+press-key: "ArrowDown"
+assert: ".search-results.active > a:focus:nth-of-type(3)"
+
+// Now switch to the second tab, then back to the first one, then arrow back up.
+press-key: "ArrowRight"
+assert: ".search-results.active:nth-of-type(2) > a:focus:nth-of-type(1)"
+press-key: "ArrowLeft"
+assert: ".search-results.active:nth-of-type(1) > a:focus:nth-of-type(3)"
+press-key: "ArrowUp"
+assert: ".search-results.active > a:focus:nth-of-type(2)"
+press-key: "ArrowUp"
+assert: ".search-results.active > a:focus:nth-of-type(1)"
+press-key: "ArrowUp"
+assert: ".search-input:focus"
+press-key: "ArrowDown"
+assert: ".search-results.active > a:focus:nth-of-type(1)"
diff --git a/src/test/rustdoc/issue-102154.rs b/src/test/rustdoc/issue-102154.rs
new file mode 100644
index 00000000000..b36f270806f
--- /dev/null
+++ b/src/test/rustdoc/issue-102154.rs
@@ -0,0 +1,13 @@
+trait A<Y, N> {
+    type B;
+}
+type MaybeBox<T> = <T as A<T, Box<T>>>::B;
+struct P {
+    t: MaybeBox<P>
+}
+impl<Y, N> A<Y, N> for P {
+    type B = N;
+}
+fn main() {
+    let t: MaybeBox<P>;
+}
diff --git a/src/test/ui/suggestions/dont-suggest-ufcs-for-const.rs b/src/test/ui/suggestions/dont-suggest-ufcs-for-const.rs
new file mode 100644
index 00000000000..06cf243f1b4
--- /dev/null
+++ b/src/test/ui/suggestions/dont-suggest-ufcs-for-const.rs
@@ -0,0 +1,4 @@
+fn main() {
+    1_u32.MAX();
+    //~^ ERROR no method named `MAX` found for type `u32` in the current scope
+}
diff --git a/src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr b/src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr
new file mode 100644
index 00000000000..04e0511d788
--- /dev/null
+++ b/src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr
@@ -0,0 +1,15 @@
+error[E0599]: no method named `MAX` found for type `u32` in the current scope
+  --> $DIR/dont-suggest-ufcs-for-const.rs:2:11
+   |
+LL |     1_u32.MAX();
+   |     ------^^^--
+   |     |     |
+   |     |     this is an associated function, not a method
+   |     help: use associated function syntax instead: `u32::MAX()`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+   = note: the candidate is defined in an impl for the type `u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed
new file mode 100644
index 00000000000..8d96cf590c3
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed
@@ -0,0 +1,15 @@
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    fn test() -> i32 { 1 }
+}
+
+fn main() {
+    let x = Box::new(Foo(1i32));
+    Foo::<i32>::test();
+    //~^ ERROR no method named `test` found for struct `Box<Foo<i32>>` in the current scope
+}
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs
new file mode 100644
index 00000000000..186901f75a8
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs
@@ -0,0 +1,15 @@
+// run-rustfix
+
+#![allow(unused)]
+
+struct Foo<T>(T);
+
+impl<T> Foo<T> {
+    fn test() -> i32 { 1 }
+}
+
+fn main() {
+    let x = Box::new(Foo(1i32));
+    x.test();
+    //~^ ERROR no method named `test` found for struct `Box<Foo<i32>>` in the current scope
+}
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr
new file mode 100644
index 00000000000..00fb96f0326
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr
@@ -0,0 +1,19 @@
+error[E0599]: no method named `test` found for struct `Box<Foo<i32>>` in the current scope
+  --> $DIR/suggest-assoc-fn-call-deref.rs:13:7
+   |
+LL |     x.test();
+   |     --^^^^--
+   |     | |
+   |     | this is an associated function, not a method
+   |     help: use associated function syntax instead: `Foo::<i32>::test()`
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in an impl for the type `Foo<T>`
+  --> $DIR/suggest-assoc-fn-call-deref.rs:8:5
+   |
+LL |     fn test() -> i32 { 1 }
+   |     ^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 9a682fbe604..d13b34a66cc 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -199,12 +199,12 @@ pub fn first_node_in_macro(cx: &LateContext<'_>, node: &impl HirNode) -> Option<
 pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
     let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
     matches!(
-        name.as_str(),
-        "core_panic_macro"
-            | "std_panic_macro"
-            | "core_panic_2015_macro"
-            | "std_panic_2015_macro"
-            | "core_panic_2021_macro"
+        name,
+        sym::core_panic_macro
+            | sym::std_panic_macro
+            | sym::core_panic_2015_macro
+            | sym::std_panic_2015_macro
+            | sym::core_panic_2021_macro
     )
 }