From e1636b83e323415539d6b487dc1571728d13eb81 Mon Sep 17 00:00:00 2001 From: Andrew Pollack Date: Tue, 1 Nov 2022 17:02:30 +0000 Subject: [PATCH 01/20] Adding Fuchsia compiler testing script, docs --- src/ci/docker/scripts/fuchsia-test-runner.py | 1041 +++++++++++++++++ src/doc/rustc/src/platform-support/fuchsia.md | 56 +- 2 files changed, 1095 insertions(+), 2 deletions(-) create mode 100644 src/ci/docker/scripts/fuchsia-test-runner.py 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 0000000000000..a2708d16947f0 --- /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 1ff6003c121cd..62cad19d0ec33 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 From ce10ac0d6a047d9a537b68b75c89ddc6859c7d4d Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 13 Nov 2022 11:32:57 +0100 Subject: [PATCH 02/20] remove leading newlines from `NonZero*` doc examples --- library/core/src/num/nonzero.rs | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5b7521220acdb..6a417b54daa93 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -321,7 +321,6 @@ macro_rules! nonzero_unsigned_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] @@ -356,7 +355,6 @@ macro_rules! nonzero_unsigned_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] @@ -391,8 +389,8 @@ macro_rules! nonzero_unsigned_operations { /// /// ``` /// #![feature(nonzero_ops)] - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] @@ -420,7 +418,6 @@ macro_rules! nonzero_unsigned_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] @@ -461,7 +458,6 @@ macro_rules! nonzero_unsigned_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")] @@ -486,7 +482,6 @@ macro_rules! nonzero_unsigned_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")] @@ -526,7 +521,6 @@ macro_rules! nonzero_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] @@ -556,7 +550,6 @@ macro_rules! nonzero_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] @@ -591,7 +584,6 @@ macro_rules! nonzero_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] @@ -626,7 +618,6 @@ macro_rules! nonzero_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] @@ -662,7 +653,6 @@ macro_rules! nonzero_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] @@ -905,7 +895,6 @@ macro_rules! nonzero_unsigned_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] @@ -941,7 +930,6 @@ macro_rules! nonzero_unsigned_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] @@ -986,8 +974,8 @@ macro_rules! nonzero_unsigned_signed_operations { /// /// ``` /// #![feature(nonzero_ops)] - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] @@ -1014,7 +1002,6 @@ macro_rules! nonzero_unsigned_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] @@ -1058,7 +1045,6 @@ macro_rules! nonzero_unsigned_signed_operations { /// /// ``` #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] @@ -1162,8 +1148,8 @@ macro_rules! nonzero_min_max_unsigned { /// /// ``` /// #![feature(nonzero_min_max)] - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")] /// ``` #[unstable(feature = "nonzero_min_max", issue = "89065")] @@ -1177,8 +1163,8 @@ macro_rules! nonzero_min_max_unsigned { /// /// ``` /// #![feature(nonzero_min_max)] - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")] /// ``` #[unstable(feature = "nonzero_min_max", issue = "89065")] @@ -1204,8 +1190,8 @@ macro_rules! nonzero_min_max_signed { /// /// ``` /// #![feature(nonzero_min_max)] - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")] /// ``` #[unstable(feature = "nonzero_min_max", issue = "89065")] @@ -1223,8 +1209,8 @@ macro_rules! nonzero_min_max_signed { /// /// ``` /// #![feature(nonzero_min_max)] - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")] /// ``` #[unstable(feature = "nonzero_min_max", issue = "89065")] From cd2fb430daa487c1a904a2e3dc8494f23dea6df6 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 13 Nov 2022 22:20:54 +0530 Subject: [PATCH 03/20] Update compiler-builtins This was originally a part of https://github.com/rust-lang/rust/pull/100316. However, extracting it to a seperate PR should help with any extra testing that might be needed. Signed-off-by: Ayush Singh --- library/std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index daa6976c30143..c10bfde4ddf79 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } libc = { version = "0.2.135", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.73" } +compiler_builtins = { version = "0.1.82" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] } From 409c3ce44165d61ad573cacccf3f462ad834d524 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 13 Nov 2022 18:49:21 +0000 Subject: [PATCH 04/20] Remove unused diagnostic items --- compiler/rustc_span/src/symbol.rs | 15 --------------- library/core/src/fmt/mod.rs | 1 - library/core/src/macros/mod.rs | 12 ------------ library/core/src/ops/function.rs | 6 ------ library/core/src/panic.rs | 2 -- library/std/src/net/ip_addr.rs | 2 -- 6 files changed, 38 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b48db73618b0b..4d1d25889f1dd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -190,9 +190,6 @@ symbols! { Error, File, FileType, - Fn, - FnMut, - FnOnce, FormatSpec, Formatter, From, @@ -462,7 +459,6 @@ symbols! { cfg_doctest, cfg_eval, cfg_hide, - cfg_macro, cfg_panic, cfg_sanitize, cfg_target_abi, @@ -495,19 +491,16 @@ symbols! { cold, collapse_debuginfo, column, - column_macro, compare_and_swap, compare_exchange, compare_exchange_weak, compile_error, - compile_error_macro, compiler, compiler_builtins, compiler_fence, concat, concat_bytes, concat_idents, - concat_macro, conservative_impl_trait, console, const_allocate, @@ -724,7 +717,6 @@ symbols! { field, field_init_shorthand, file, - file_macro, fill, finish, flags, @@ -826,7 +818,6 @@ symbols! { include, include_bytes, include_bytes_macro, - include_macro, include_str, include_str_macro, inclusive_range_syntax, @@ -881,7 +872,6 @@ symbols! { lifetimes, likely, line, - line_macro, link, link_args, link_cfg, @@ -926,7 +916,6 @@ symbols! { masked, match_beginning_vert, match_default_bindings, - matches_macro, maxnumf32, maxnumf64, may_dangle, @@ -965,7 +954,6 @@ symbols! { modifiers, module, module_path, - module_path_macro, more_qualified_paths, more_struct_aliases, movbe_target_feature, @@ -1103,7 +1091,6 @@ symbols! { plugins, pointee_trait, pointer, - pointer_trait_fmt, poll, position, post_dash_lto: "post-lto", @@ -1449,7 +1436,6 @@ symbols! { str_trim_start, strict_provenance, stringify, - stringify_macro, struct_field_attributes, struct_inherit, struct_variant, @@ -1568,7 +1554,6 @@ symbols! { unreachable_2015, unreachable_2015_macro, unreachable_2021, - unreachable_2021_macro, unreachable_code, unreachable_display, unreachable_macro, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c8d2855056757..2adc968bd4692 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1054,7 +1054,6 @@ pub trait UpperHex { pub trait Pointer { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_diagnostic_item = "pointer_trait_fmt"] fn fmt(&self, f: &mut Formatter<'_>) -> Result; } diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 32bdc26bc51ad..34247c0584508 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -338,7 +338,6 @@ pub macro debug_assert_matches($($arg:tt)*) { /// ``` #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")] macro_rules! matches { ($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { match $expression { @@ -820,7 +819,6 @@ pub(crate) mod builtin { #[stable(feature = "compile_error_macro", since = "1.20.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "compile_error_macro")] macro_rules! compile_error { ($msg:expr $(,)?) => {{ /* compiler built-in */ }}; } @@ -944,7 +942,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "env_macro")] macro_rules! env { ($name:expr $(,)?) => {{ /* compiler built-in */ }}; ($name:expr, $error_msg:expr $(,)?) => {{ /* compiler built-in */ }}; @@ -973,7 +970,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "option_env_macro")] macro_rules! option_env { ($name:expr $(,)?) => {{ /* compiler built-in */ }}; } @@ -1058,7 +1054,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "concat_macro")] macro_rules! concat { ($($e:expr),* $(,)?) => {{ /* compiler built-in */ }}; } @@ -1084,7 +1079,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "line_macro")] macro_rules! line { () => { /* compiler built-in */ @@ -1124,7 +1118,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "column_macro")] macro_rules! column { () => { /* compiler built-in */ @@ -1150,7 +1143,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "file_macro")] macro_rules! file { () => { /* compiler built-in */ @@ -1175,7 +1167,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "stringify_macro")] macro_rules! stringify { ($($t:tt)*) => { /* compiler built-in */ @@ -1282,7 +1273,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "module_path_macro")] macro_rules! module_path { () => { /* compiler built-in */ @@ -1316,7 +1306,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "cfg_macro")] macro_rules! cfg { ($($cfg:tt)*) => { /* compiler built-in */ @@ -1367,7 +1356,6 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "include_macro")] macro_rules! include { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 11b43b621c7b8..2bcc9779ec7f2 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -57,7 +57,6 @@ use crate::marker::Tuple; #[cfg(bootstrap)] #[lang = "fn"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "Fn"] #[rustc_paren_sugar] #[rustc_on_unimplemented( on( @@ -137,7 +136,6 @@ pub trait Fn: FnMut { #[cfg(not(bootstrap))] #[lang = "fn"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "Fn"] #[rustc_paren_sugar] #[rustc_on_unimplemented( on( @@ -226,7 +224,6 @@ pub trait Fn: FnMut { #[cfg(bootstrap)] #[lang = "fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "FnMut"] #[rustc_paren_sugar] #[rustc_on_unimplemented( on( @@ -314,7 +311,6 @@ pub trait FnMut: FnOnce { #[cfg(not(bootstrap))] #[lang = "fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "FnMut"] #[rustc_paren_sugar] #[rustc_on_unimplemented( on( @@ -395,7 +391,6 @@ pub trait FnMut: FnOnce { #[cfg(bootstrap)] #[lang = "fn_once"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "FnOnce"] #[rustc_paren_sugar] #[rustc_on_unimplemented( on( @@ -480,7 +475,6 @@ pub trait FnOnce { #[cfg(not(bootstrap))] #[lang = "fn_once"] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_diagnostic_item = "FnOnce"] #[rustc_paren_sugar] #[rustc_on_unimplemented( on( diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 00b63dfbd0693..959bdea7dba98 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -43,7 +43,6 @@ pub macro panic_2015 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(core_panic, const_format_args)] -#[rustc_diagnostic_item = "core_panic_2021_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2021 { () => ( @@ -80,7 +79,6 @@ pub macro unreachable_2015 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")] #[allow_internal_unstable(core_panic)] -#[rustc_diagnostic_item = "unreachable_2021_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro unreachable_2021 { () => ( diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs index 4f14fc28038ad..5453853e1381a 100644 --- a/library/std/src/net/ip_addr.rs +++ b/library/std/src/net/ip_addr.rs @@ -73,7 +73,6 @@ pub enum IpAddr { /// assert!("0xcb.0x0.0x71.0x00".parse::().is_err()); // all octets are in hex /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Ipv4Addr")] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv4Addr { octets: [u8; 4], @@ -156,7 +155,6 @@ pub struct Ipv4Addr { /// assert_eq!(localhost.is_loopback(), true); /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Ipv6Addr")] #[stable(feature = "rust1", since = "1.0.0")] pub struct Ipv6Addr { octets: [u8; 16], From 4ed2bf68021dac59a9a32537aa983aed8d2c0439 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 13 Nov 2022 20:05:32 +0000 Subject: [PATCH 05/20] Remove unused symbols --- compiler/rustc_span/src/symbol.rs | 37 ------------------------------- 1 file changed, 37 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4d1d25889f1dd..d136d19431e61 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -170,8 +170,6 @@ symbols! { Count, Cow, Debug, - DebugStruct, - DebugTuple, Decodable, Decoder, DecorateLint, @@ -208,7 +206,6 @@ symbols! { Input, Into, IntoDiagnostic, - IntoFuture, IntoIterator, IoRead, IoWrite, @@ -253,7 +250,6 @@ symbols! { Pointer, Poll, ProcMacro, - ProcMacroHack, ProceduralMasqueradeDummyType, Range, RangeFrom, @@ -329,7 +325,6 @@ symbols! { abi_vectorcall, abi_x86_interrupt, abort, - aborts, add, add_assign, add_with_overflow, @@ -341,7 +336,6 @@ symbols! { align, align_offset, alignment, - alignstack, all, alloc, alloc_error_handler, @@ -430,7 +424,6 @@ symbols! { bool, borrowck_graphviz_format, borrowck_graphviz_postflow, - borrowck_graphviz_preflow, box_free, box_patterns, box_syntax, @@ -466,7 +459,6 @@ symbols! { cfg_target_feature, cfg_target_has_atomic, cfg_target_has_atomic_equal_alignment, - cfg_target_has_atomic_load_store, cfg_target_thread_local, cfg_target_vendor, cfg_version, @@ -491,7 +483,6 @@ symbols! { cold, collapse_debuginfo, column, - compare_and_swap, compare_exchange, compare_exchange_weak, compile_error, @@ -521,7 +512,6 @@ symbols! { const_fn_unsize, const_for, const_format_args, - const_generic_defaults, const_generics, const_generics_defaults, const_if_match, @@ -540,20 +530,16 @@ symbols! { const_trait, const_trait_bound_opt_out, const_trait_impl, - const_transmute, const_try, constant, constructor, - contents, context, - convert, copy, copy_closures, copy_nonoverlapping, copysignf32, copysignf64, core, - core_intrinsics, core_panic, core_panic_2015_macro, core_panic_macro, @@ -591,7 +577,6 @@ symbols! { debug_assertions, debug_struct, debug_struct_fields_finish, - debug_trait_builder, debug_tuple, debug_tuple_fields_finish, debugger_visualizer, @@ -623,7 +608,6 @@ symbols! { discriminant_type, discriminant_value, dispatch_from_dyn, - display_trait, div, div_assign, doc, @@ -637,7 +621,6 @@ symbols! { doc_primitive, doc_spotlight, doctest, - document_private_items, dotdot: "..", dotdot_in_tuple_patterns, dotdoteq_in_patterns, @@ -654,7 +637,6 @@ symbols! { dyn_star, dyn_trait, e, - edition_macro_pats, edition_panic, eh_catch_typeinfo, eh_personality, @@ -667,7 +649,6 @@ symbols! { encode, end, env, - env_macro, eprint_macro, eprintln_macro, eq, @@ -718,7 +699,6 @@ symbols! { field_init_shorthand, file, fill, - finish, flags, float, float_to_int_unchecked, @@ -727,8 +707,6 @@ symbols! { fmaf32, fmaf64, fmt, - fmt_as_str, - fmt_internals, fmul_fast, fn_align, fn_must_use, @@ -743,7 +721,6 @@ symbols! { format_args_macro, format_args_nl, format_macro, - fp, freeze, freg, frem_fast, @@ -806,7 +783,6 @@ symbols! { ignore, impl_header_lifetime_elision, impl_lint_pass, - impl_macros, impl_trait_in_bindings, impl_trait_in_fn_trait_return, implied_by, @@ -835,7 +811,6 @@ symbols! { instruction_set, integer_: "integer", integral, - intel, into_future, into_iter, intra_doc_pointers, @@ -1048,7 +1023,6 @@ symbols! { optin_builtin_traits, option, option_env, - option_env_macro, options, or, or_patterns, @@ -1117,7 +1091,6 @@ symbols! { proc_dash_macro: "proc-macro", proc_macro, proc_macro_attribute, - proc_macro_def_site, proc_macro_derive, proc_macro_expr, proc_macro_gen, @@ -1218,9 +1191,6 @@ symbols! { rust_cold_cc, rust_eh_catch_typeinfo, rust_eh_personality, - rust_eh_register_frames, - rust_eh_unregister_frames, - rust_oom, rustc, rustc_allocator, rustc_allocator_zeroed, @@ -1293,7 +1263,6 @@ symbols! { rustc_serialize, rustc_skip_array_during_method_dispatch, rustc_specialization_trait, - rustc_stable, rustc_std_internal_symbol, rustc_strict_coherence, rustc_symbol_name, @@ -1421,7 +1390,6 @@ symbols! { static_recursion, staticlib, std, - std_inject, std_panic, std_panic_2015_macro, std_panic_macro, @@ -1463,10 +1431,8 @@ symbols! { target_has_atomic_load_store, target_os, target_pointer_width, - target_target_vendor, target_thread_local, target_vendor, - task, tbm_target_feature, termination, termination_trait, @@ -1478,7 +1444,6 @@ symbols! { test_removed_feature, test_runner, test_unstable_lint, - then_with, thread, thread_local, thread_local_macro, @@ -1510,7 +1475,6 @@ symbols! { try_trait_v2, tt, tuple, - tuple_from_req, tuple_indexing, tuple_trait, two_phase, @@ -1572,7 +1536,6 @@ symbols! { from crates.io via `Cargo.toml` instead?", untagged_unions, unused_imports, - unused_qualifications, unwind, unwind_attributes, unwind_safe_trait, From 25acee5494db43bd010c7a2615fae71ce905afe7 Mon Sep 17 00:00:00 2001 From: mejrs <> Date: Sun, 13 Nov 2022 22:48:27 +0100 Subject: [PATCH 06/20] Remove dead NoneError error handling --- compiler/rustc_span/src/symbol.rs | 1 - .../src/traits/error_reporting/mod.rs | 43 ++++--------------- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b48db73618b0b..c35bb0cc475d7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1035,7 +1035,6 @@ symbols! { non_exhaustive, non_exhaustive_omitted_patterns_lint, non_modrs_mods, - none_error, nontemporal_store, noop_method_borrow, noop_method_clone, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 98c13ffdafb02..41b252a82651c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -650,41 +650,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { )) ); - if is_try_conversion { - let none_error = self - .tcx - .get_diagnostic_item(sym::none_error) - .map(|def_id| tcx.type_of(def_id)); - let should_convert_option_to_result = - Some(trait_ref.skip_binder().substs.type_at(1)) == none_error; - let should_convert_result_to_option = - Some(trait_ref.self_ty().skip_binder()) == none_error; - if should_convert_option_to_result { - err.span_suggestion_verbose( - span.shrink_to_lo(), - "consider converting the `Option` into a `Result` \ - using `Option::ok_or` or `Option::ok_or_else`", - ".ok_or_else(|| /* error value */)", - Applicability::HasPlaceholders, - ); - } else if should_convert_result_to_option { - err.span_suggestion_verbose( - span.shrink_to_lo(), - "consider converting the `Result` into an `Option` \ - using `Result::ok`", - ".ok()", - Applicability::MachineApplicable, - ); - } - if let Some(ret_span) = self.return_type_span(&obligation) { - err.span_label( - ret_span, - &format!( - "expected `{}` because of this", - trait_ref.skip_binder().self_ty() - ), - ); - } + if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { + err.span_label( + ret_span, + &format!( + "expected `{}` because of this", + trait_ref.skip_binder().self_ty() + ), + ); } if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() { From 2575e4da3b09974efd84aa94ca98555bcd898965 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 13 Nov 2022 14:56:22 -0700 Subject: [PATCH 07/20] rustdoc: remove unused CSS `code { opacity: 1 }` According to https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/CSS.20cleanup this style was added for declarations that no longer use opacity. --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 3f295b96dc56d..d195c9cf6f9ff 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); From 29fe28fcfc01f6b850744cc918dbc07a82978755 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 13 Nov 2022 22:58:20 +0000 Subject: [PATCH 08/20] Fix clippy and rustdoc please, please, don't match on `Symbol::as_str`s, every time you do, somewhere in the world another waffle becomes sad... --- compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/panic.rs | 1 + src/tools/clippy/clippy_utils/src/macros.rs | 12 ++++++------ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d136d19431e61..58e323d42ce8c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -542,6 +542,7 @@ symbols! { core, core_panic, core_panic_2015_macro, + core_panic_2021_macro, core_panic_macro, cosf32, cosf64, @@ -621,6 +622,7 @@ symbols! { doc_primitive, doc_spotlight, doctest, + document_private_items, dotdot: "..", dotdot_in_tuple_patterns, dotdoteq_in_patterns, diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 959bdea7dba98..461b70c32f36e 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -43,6 +43,7 @@ pub macro panic_2015 { #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] #[allow_internal_unstable(core_panic, const_format_args)] +#[rustc_diagnostic_item = "core_panic_2021_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2021 { () => ( diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 9a682fbe604ff..d13b34a66cca7 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 ) } From 9985f4611b0d52e7faf6fc68adcdbced786871a9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Nov 2022 13:49:08 +1100 Subject: [PATCH 09/20] Clarify `expand_struct_method_body`. Spotted by @RalfJung. This causes no behavioural changes. --- compiler/rustc_builtin_macros/src/deriving/generic/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 16ee3aa89bb12..7b3c73de6de7d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1060,18 +1060,17 @@ impl<'a> MethodDef<'a> { trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, true); mk_body(cx, selflike_fields) } else { - // Neither packed nor copy. Need to use ref patterns. + // Packed and not copy. Need to use ref patterns. let prefixes: Vec<_> = (0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect(); - let addr_of = always_copy; + let addr_of = false; let selflike_fields = trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, addr_of); let mut body = mk_body(cx, selflike_fields); let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); - let by_ref = ByRef::from(is_packed && !always_copy); let patterns = - trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, by_ref); + trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, ByRef::Yes); // Do the let-destructuring. let mut stmts: Vec<_> = iter::zip(selflike_args, patterns) From 96280b6a1d39af0d6305cfeb53a2468964e04155 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Nov 2022 13:59:54 +1100 Subject: [PATCH 10/20] Remove `addr_of` argument from `create_struct_pattern_fields`. Because it's always false. --- .../rustc_builtin_macros/src/deriving/generic/mod.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 7b3c73de6de7d..73cf1989341e8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1063,9 +1063,7 @@ impl<'a> MethodDef<'a> { // Packed and not copy. Need to use ref patterns. let prefixes: Vec<_> = (0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect(); - let addr_of = false; - let selflike_fields = - trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, addr_of); + let selflike_fields = trait_.create_struct_pattern_fields(cx, struct_def, &prefixes); let mut body = mk_body(cx, selflike_fields); let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); @@ -1251,9 +1249,7 @@ impl<'a> MethodDef<'a> { // A single arm has form (&VariantK, &VariantK, ...) => BodyK // (see "Final wrinkle" note below for why.) - let addr_of = false; // because enums can't be repr(packed) - let fields = - trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes, addr_of); + let fields = trait_.create_struct_pattern_fields(cx, &variant.data, &prefixes); let sp = variant.span.with_ctxt(trait_.span.ctxt()); let variant_path = cx.path(sp, vec![type_ident, variant.ident]); @@ -1516,15 +1512,13 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt<'_>, struct_def: &'a VariantData, prefixes: &[String], - addr_of: bool, ) -> Vec { self.create_fields(struct_def, |i, _struct_field, sp| { prefixes .iter() .map(|prefix| { let ident = self.mk_pattern_ident(prefix, i); - let expr = cx.expr_path(cx.path_ident(sp, ident)); - if addr_of { cx.expr_addr_of(sp, expr) } else { expr } + cx.expr_path(cx.path_ident(sp, ident)) }) .collect() }) From 111db7d3a87ff0bfc8753e4d03563de2539dd9da Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 14 Nov 2022 15:43:10 +1100 Subject: [PATCH 11/20] Remove TraitDef::generics. Because it's always empty. --- compiler/rustc_ast/src/ast.rs | 16 +++--- .../src/deriving/bounds.rs | 2 - .../src/deriving/clone.rs | 1 - .../src/deriving/cmp/eq.rs | 1 - .../src/deriving/cmp/ord.rs | 1 - .../src/deriving/cmp/partial_eq.rs | 1 - .../src/deriving/cmp/partial_ord.rs | 1 - .../src/deriving/debug.rs | 1 - .../src/deriving/decodable.rs | 1 - .../src/deriving/default.rs | 1 - .../src/deriving/encodable.rs | 1 - .../src/deriving/generic/mod.rs | 52 +++++++++---------- .../rustc_builtin_macros/src/deriving/hash.rs | 1 - 13 files changed, 33 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4ef43735a62c8..9cd954e3199de 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -392,15 +392,7 @@ pub struct Generics { impl Default for Generics { /// Creates an instance of `Generics`. fn default() -> Generics { - Generics { - params: Vec::new(), - where_clause: WhereClause { - has_where_token: false, - predicates: Vec::new(), - span: DUMMY_SP, - }, - span: DUMMY_SP, - } + Generics { params: Vec::new(), where_clause: Default::default(), span: DUMMY_SP } } } @@ -415,6 +407,12 @@ pub struct WhereClause { pub span: Span, } +impl Default for WhereClause { + fn default() -> WhereClause { + WhereClause { has_where_token: false, predicates: Vec::new(), span: DUMMY_SP } + } +} + /// A single predicate in a where-clause. #[derive(Clone, Encodable, Decodable, Debug)] pub enum WherePredicate { diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 7bd344467d032..a5aa46aae77a7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -1,4 +1,3 @@ -use crate::deriving::generic::ty::*; use crate::deriving::generic::*; use crate::deriving::path_std; @@ -18,7 +17,6 @@ pub fn expand_deriving_copy( path: path_std!(marker::Copy), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: true, methods: Vec::new(), associated_types: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index fa8685f5f4e56..70e28d29dc1a8 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -74,7 +74,6 @@ pub fn expand_deriving_clone( path: path_std!(clone::Clone), skip_path_as_bound: false, additional_bounds: bounds, - generics: Bounds::empty(), supports_unions: true, methods: vec![MethodDef { name: sym::clone, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs index eab67b0d354cf..4ed32c4274b6a 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs @@ -27,7 +27,6 @@ pub fn expand_deriving_eq( path: path_std!(cmp::Eq), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: true, methods: vec![MethodDef { name: sym::assert_receiver_is_total_eq, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs index 7f117981a9a2f..7e36389fd168d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs @@ -21,7 +21,6 @@ pub fn expand_deriving_ord( path: path_std!(cmp::Ord), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::cmp, diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 236cbccaf9fee..53d7b05e59373 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -85,7 +85,6 @@ pub fn expand_deriving_partial_eq( path: path_std!(cmp::PartialEq), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods, associated_types: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 4173403a1b84a..b619719570c16 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -39,7 +39,6 @@ pub fn expand_deriving_partial_ord( path: path_std!(cmp::PartialOrd), skip_path_as_bound: false, additional_bounds: vec![], - generics: Bounds::empty(), supports_unions: false, methods: vec![partial_cmp_def], associated_types: Vec::new(), diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 2cf614ed9476c..faffb9f8abc5b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -22,7 +22,6 @@ pub fn expand_deriving_debug( path: path_std!(fmt::Debug), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::fmt, diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index d669f616802fe..71b523ac6aca9 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -25,7 +25,6 @@ pub fn expand_deriving_rustc_decodable( path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::decode, diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 17df9fb279ad6..66007e040479e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -26,7 +26,6 @@ pub fn expand_deriving_default( path: Path::new(vec![kw::Default, sym::Default]), skip_path_as_bound: has_a_default_variant(item), additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: kw::Default, diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs index f83f58b97d38f..b5ed4bfb1c7a7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs @@ -109,7 +109,6 @@ pub fn expand_deriving_rustc_encodable( path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global), skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::encode, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 73cf1989341e8..b873018660e75 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -195,9 +195,6 @@ pub struct TraitDef<'a> { /// other than the current trait pub additional_bounds: Vec, - /// Any extra lifetimes and/or bounds, e.g., `D: serialize::Decoder` - pub generics: Bounds, - /// Can this trait be derived for unions? pub supports_unions: bool, @@ -581,19 +578,21 @@ impl<'a> TraitDef<'a> { }) }); - let Generics { mut params, mut where_clause, .. } = - self.generics.to_generics(cx, self.span, type_ident, generics); + let mut where_clause = ast::WhereClause::default(); where_clause.span = generics.where_clause.span; let ctxt = self.span.ctxt(); let span = generics.span.with_ctxt(ctxt); // Create the generic parameters - params.extend(generics.params.iter().map(|param| match ¶m.kind { - GenericParamKind::Lifetime { .. } => param.clone(), - GenericParamKind::Type { .. } => { - // I don't think this can be moved out of the loop, since - // a GenericBound requires an ast id - let bounds: Vec<_> = + let params: Vec<_> = generics + .params + .iter() + .map(|param| match ¶m.kind { + GenericParamKind::Lifetime { .. } => param.clone(), + GenericParamKind::Type { .. } => { + // I don't think this can be moved out of the loop, since + // a GenericBound requires an ast id + let bounds: Vec<_> = // extra restrictions on the generics parameters to the // type being derived upon self.additional_bounds.iter().map(|p| { @@ -606,21 +605,22 @@ impl<'a> TraitDef<'a> { param.bounds.iter().cloned() ).collect(); - cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) - } - GenericParamKind::Const { ty, kw_span, .. } => { - let const_nodefault_kind = GenericParamKind::Const { - ty: ty.clone(), - kw_span: kw_span.with_ctxt(ctxt), - - // We can't have default values inside impl block - default: None, - }; - let mut param_clone = param.clone(); - param_clone.kind = const_nodefault_kind; - param_clone - } - })); + cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None) + } + GenericParamKind::Const { ty, kw_span, .. } => { + let const_nodefault_kind = GenericParamKind::Const { + ty: ty.clone(), + kw_span: kw_span.with_ctxt(ctxt), + + // We can't have default values inside impl block + default: None, + }; + let mut param_clone = param.clone(); + param_clone.kind = const_nodefault_kind; + param_clone + } + }) + .collect(); // and similarly for where clauses where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| { diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs index 6e9d5f08b9443..53b6620efd6c0 100644 --- a/compiler/rustc_builtin_macros/src/deriving/hash.rs +++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs @@ -24,7 +24,6 @@ pub fn expand_deriving_hash( path, skip_path_as_bound: false, additional_bounds: Vec::new(), - generics: Bounds::empty(), supports_unions: false, methods: vec![MethodDef { name: sym::hash, From a9e4176bc868bd0d5b1f9a4dcff5aed5c22ad3f8 Mon Sep 17 00:00:00 2001 From: koka Date: Mon, 14 Nov 2022 22:55:50 +0900 Subject: [PATCH 12/20] Specify language of code comment to generate document --- compiler/rustc_lint/src/let_underscore.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 78f355ec3d0ae..c8939256bbbf6 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -11,7 +11,8 @@ declare_lint! { /// scope. /// /// ### Example - /// ``` + /// + /// ```rust /// struct SomeStruct; /// impl Drop for SomeStruct { /// fn drop(&mut self) { From e6baae576c9b474d1946a1d0f98692c7a3e62549 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 14 Nov 2022 15:14:54 +0100 Subject: [PATCH 13/20] Fix missing minification for static files --- src/librustdoc/html/static_files.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index afe920b7fa1e0..b4d4150cddbb8 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 { - 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() From 212ce1f10cba1a1c9abd856664dfa5c0a47a59bc Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Mon, 14 Nov 2022 14:59:32 +0000 Subject: [PATCH 14/20] [llvm-wrapper] adapt for LLVM API change --- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 0d9b5a57b69a2..85c520a7911f3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -9,7 +9,7 @@ #include "llvm/IR/IntrinsicsARM.h" #include "llvm/IR/Mangler.h" #if LLVM_VERSION_GE(16, 0) -#include "llvm/IR/ModRef.h" +#include "llvm/Support/ModRef.h" #endif #include "llvm/Object/Archive.h" #include "llvm/Object/COFFImportFile.h" From 3f697b85f2196ea7d2a5d4fa1f88c39e63871d39 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Nov 2022 17:25:37 +0000 Subject: [PATCH 15/20] Drive-by: actual -> rcvr_ty --- .../rustc_hir_typeck/src/method/suggest.rs | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 43a5145b7e74d..94df6817bf526 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -263,15 +263,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) => { let tcx = self.tcx; - let actual = self.resolve_vars_if_possible(rcvr_ty); - let ty_str = self.ty_to_string(actual); + let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); + let ty_str = self.ty_to_string(rcvr_ty); let is_method = mode == Mode::MethodCall; let item_kind = if is_method { "method" - } else if actual.is_enum() { + } else if rcvr_ty.is_enum() { "variant or associated item" } else { - match (item_name.as_str().chars().next(), actual.is_fresh_ty()) { + match (item_name.as_str().chars().next(), rcvr_ty.is_fresh_ty()) { (Some(name), false) if name.is_lowercase() => "function or associated item", (Some(_), false) => "associated item", (Some(_), true) | (None, false) => "variant or associated item", @@ -280,9 +280,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if self.suggest_wrapping_range_with_parens( - tcx, actual, source, span, item_name, &ty_str, + tcx, rcvr_ty, source, span, item_name, &ty_str, ) || self.suggest_constraining_numerical_ty( - tcx, actual, source, span, item_kind, item_name, &ty_str, + tcx, rcvr_ty, source, span, item_kind, item_name, &ty_str, ) { return None; } @@ -290,9 +290,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't show generic arguments when the method can't be found in any implementation (#81576). let mut ty_str_reported = ty_str.clone(); - if let ty::Adt(_, generics) = actual.kind() { + if let ty::Adt(_, generics) = rcvr_ty.kind() { if generics.len() > 0 { - let mut autoderef = self.autoderef(span, actual); + let mut autoderef = self.autoderef(span, rcvr_ty); let candidate_found = autoderef.any(|(ty, _)| { if let ty::Adt(adt_def, _) = ty.kind() { self.tcx @@ -321,16 +321,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "no {} named `{}` found for {} `{}` in the current scope", item_kind, item_name, - actual.prefix_string(self.tcx), + rcvr_ty.prefix_string(self.tcx), ty_str_reported, ); - if actual.references_error() { + if rcvr_ty.references_error() { err.downgrade_to_delayed_bug(); } if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source { self.suggest_await_before_method( - &mut err, item_name, actual, cal, span, + &mut err, item_name, rcvr_ty, cal, span, ); } if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) { @@ -341,7 +341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } - if let ty::RawPtr(_) = &actual.kind() { + if let ty::RawPtr(_) = &rcvr_ty.kind() { err.note( "try using `<*const T>::as_ref()` to get a reference to the \ type behind the pointer: https://doc.rust-lang.org/std/\ @@ -353,7 +353,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - let ty_span = match actual.kind() { + let ty_span = match rcvr_ty.kind() { ty::Param(param_type) => Some( param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()), ), @@ -365,7 +365,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, format!( "{item_kind} `{item_name}` not found for this {}", - actual.prefix_string(self.tcx) + rcvr_ty.prefix_string(self.tcx) ), ); } @@ -406,7 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // original type that has the associated function for accurate suggestions. // (#61411) let ty = tcx.at(span).type_of(*impl_did); - match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) { + match (&ty.peel_refs().kind(), &rcvr_ty.peel_refs().kind()) { (ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => { // If there are any inferred arguments, (`{integer}`), we should replace // them with underscores to allow the compiler to infer them @@ -451,7 +451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.ty_to_value_string(ty.peel_refs()), } } else { - self.ty_to_value_string(actual.peel_refs()) + self.ty_to_value_string(rcvr_ty.peel_refs()) }; if let SelfSource::MethodCall(_) = source { let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) && @@ -523,7 +523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut bound_spans = vec![]; let mut restrict_type_params = false; let mut unsatisfied_bounds = false; - if item_name.name == sym::count && self.is_slice_ty(actual, span) { + if item_name.name == sym::count && self.is_slice_ty(rcvr_ty, span) { let msg = "consider using `len` instead"; if let SelfSource::MethodCall(_expr) = source { err.span_suggestion_short( @@ -537,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) { let iterator_trait = self.tcx.def_path_str(iterator_trait); - err.note(&format!("`count` is defined on `{iterator_trait}`, which `{actual}` does not implement")); + err.note(&format!("`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement")); } } else if !unsatisfied_predicates.is_empty() { let mut type_params = FxHashMap::default(); @@ -876,7 +876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|(_, path)| path) .collect::>() .join("\n"); - let actual_prefix = actual.prefix_string(self.tcx); + let actual_prefix = rcvr_ty.prefix_string(self.tcx); info!("unimplemented_traits.len() == {}", unimplemented_traits.len()); let (primary_message, label) = if unimplemented_traits.len() == 1 && unimplemented_traits_only { @@ -885,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .next() .map(|(_, (trait_ref, obligation))| { if trait_ref.self_ty().references_error() - || actual.references_error() + || rcvr_ty.references_error() { // Avoid crashing. return (None, None); @@ -921,7 +921,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let label_span_not_found = |err: &mut Diagnostic| { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); - let is_string_or_ref_str = match actual.kind() { + let is_string_or_ref_str = match rcvr_ty.kind() { ty::Ref(_, ty, _) => { ty.is_str() || matches!( @@ -957,7 +957,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // different from the received one // So we avoid suggestion method with Box // for instance - self.tcx.at(span).type_of(*def_id) != actual + self.tcx.at(span).type_of(*def_id) != rcvr_ty && self.tcx.at(span).type_of(*def_id) != rcvr_ty } (Mode::Path, false, _) => true, @@ -1017,10 +1017,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't suggest (for example) `expr.field.clone()` if `expr.clone()` // can't be called due to `typeof(expr): Clone` not holding. if unsatisfied_predicates.is_empty() { - self.suggest_calling_method_on_field(&mut err, source, span, actual, item_name); + self.suggest_calling_method_on_field( + &mut err, source, span, rcvr_ty, item_name, + ); } - self.check_for_inner_self(&mut err, source, span, actual, item_name); + self.check_for_inner_self(&mut err, source, span, rcvr_ty, item_name); bound_spans.sort(); bound_spans.dedup(); @@ -1028,7 +1030,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(span, &msg); } - if actual.is_numeric() && actual.is_fresh() || restrict_type_params { + if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params { } else { self.suggest_traits_to_import( &mut err, @@ -1046,8 +1048,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Don't emit a suggestion if we found an actual method // that had unsatisfied trait bounds - if unsatisfied_predicates.is_empty() && actual.is_enum() { - let adt_def = actual.ty_adt_def().expect("enum is not an ADT"); + if unsatisfied_predicates.is_empty() && rcvr_ty.is_enum() { + let adt_def = rcvr_ty.ty_adt_def().expect("enum is not an ADT"); if let Some(suggestion) = lev_distance::find_best_match_for_name( &adt_def.variants().iter().map(|s| s.name).collect::>(), item_name.name, @@ -1062,7 +1064,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if item_name.name == sym::as_str && actual.peel_refs().is_str() { + if item_name.name == sym::as_str && rcvr_ty.peel_refs().is_str() { let msg = "remove this method call"; let mut fallback_span = true; if let SelfSource::MethodCall(expr) = source { From bf607dae3f555f714c814a03478be560ae1c37e8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Nov 2022 18:40:20 +0000 Subject: [PATCH 16/20] Move logic into method --- .../rustc_hir_typeck/src/method/suggest.rs | 256 ++++++++++-------- 1 file changed, 140 insertions(+), 116 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 94df6817bf526..821492179136b 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -398,122 +398,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { custom_span_label = true; } if static_candidates.len() == 1 { - let mut has_unsuggestable_args = false; - let ty_str = if let Some(CandidateSource::Impl(impl_did)) = - static_candidates.get(0) - { - // When the "method" is resolved through dereferencing, we really want the - // original type that has the associated function for accurate suggestions. - // (#61411) - let ty = tcx.at(span).type_of(*impl_did); - match (&ty.peel_refs().kind(), &rcvr_ty.peel_refs().kind()) { - (ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => { - // If there are any inferred arguments, (`{integer}`), we should replace - // them with underscores to allow the compiler to infer them - let infer_substs: Vec> = substs - .into_iter() - .map(|arg| { - if !arg.is_suggestable(tcx, true) { - has_unsuggestable_args = true; - match arg.unpack() { - GenericArgKind::Lifetime(_) => self - .next_region_var(RegionVariableOrigin::MiscVariable( - rustc_span::DUMMY_SP, - )) - .into(), - GenericArgKind::Type(_) => self - .next_ty_var(TypeVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: TypeVariableOriginKind::MiscVariable, - }) - .into(), - GenericArgKind::Const(arg) => self - .next_const_var( - arg.ty(), - ConstVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: ConstVariableOriginKind::MiscVariable, - }, - ) - .into(), - } - } else { - arg - } - }) - .collect::>(); - - tcx.value_path_str_with_substs( - def_actual.did(), - tcx.intern_substs(&infer_substs), - ) - } - _ => self.ty_to_value_string(ty.peel_refs()), - } - } else { - self.ty_to_value_string(rcvr_ty.peel_refs()) - }; - if let SelfSource::MethodCall(_) = source { - let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) && - let Some(assoc) = self.associated_value(*impl_did, item_name) { - let sig = self.tcx.fn_sig(assoc.def_id); - if let Some(first) = sig.inputs().skip_binder().get(0) { - if first.peel_refs() == rcvr_ty.peel_refs() { - None - } else { - Some(if first.is_region_ptr() { - if first.is_mutable_ptr() { "&mut " } else { "&" } - } else { - "" - }) - } - } else { - None - } - } else { - None - }; - let mut applicability = Applicability::MachineApplicable; - let args = if let Some((receiver, args)) = args { - // The first arg is the same kind as the receiver - let explicit_args = if first_arg.is_some() { - std::iter::once(receiver).chain(args.iter()).collect::>() - } else { - // There is no `Self` kind to infer the arguments from - if has_unsuggestable_args { - applicability = Applicability::HasPlaceholders; - } - args.iter().collect() - }; - format!( - "({}{})", - first_arg.unwrap_or(""), - explicit_args - .iter() - .map(|arg| tcx - .sess - .source_map() - .span_to_snippet(arg.span) - .unwrap_or_else(|_| { - applicability = Applicability::HasPlaceholders; - "_".to_owned() - })) - .collect::>() - .join(", "), - ) - } else { - applicability = Applicability::HasPlaceholders; - "(...)".to_owned() - }; - err.span_suggestion( - sugg_span, - "use associated function syntax instead", - format!("{}::{}{}", ty_str, item_name, args), - applicability, - ); - } else { - err.help(&format!("try with `{}::{}`", ty_str, item_name,)); - } + self.suggest_associated_call_syntax( + &mut err, + &static_candidates, + rcvr_ty, + source, + item_name, + args, + sugg_span, + ); report_candidates(span, &mut err, &mut static_candidates, sugg_span); } else if static_candidates.len() > 1 { @@ -1180,6 +1073,137 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } + /// Suggest calling `Ty::method` if `.method()` isn't found because the method + /// doesn't take a `self` receiver. + fn suggest_associated_call_syntax( + &self, + err: &mut Diagnostic, + static_candidates: &Vec, + rcvr_ty: Ty<'tcx>, + source: SelfSource<'tcx>, + item_name: Ident, + args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>, + sugg_span: Span, + ) { + let mut has_unsuggestable_args = false; + let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) { + // When the "method" is resolved through dereferencing, we really want the + // original type that has the associated function for accurate suggestions. + // (#61411) + let ty = self.tcx.type_of(*impl_did); + match (&ty.peel_refs().kind(), &rcvr_ty.peel_refs().kind()) { + (ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => { + // If there are any inferred arguments, (`{integer}`), we should replace + // them with underscores to allow the compiler to infer them + let infer_substs: Vec> = substs + .into_iter() + .map(|arg| { + if !arg.is_suggestable(self.tcx, true) { + has_unsuggestable_args = true; + match arg.unpack() { + GenericArgKind::Lifetime(_) => self + .next_region_var(RegionVariableOrigin::MiscVariable( + rustc_span::DUMMY_SP, + )) + .into(), + GenericArgKind::Type(_) => self + .next_ty_var(TypeVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + }) + .into(), + GenericArgKind::Const(arg) => self + .next_const_var( + arg.ty(), + ConstVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: ConstVariableOriginKind::MiscVariable, + }, + ) + .into(), + } + } else { + arg + } + }) + .collect::>(); + + self.tcx.value_path_str_with_substs( + def_actual.did(), + self.tcx.intern_substs(&infer_substs), + ) + } + _ => self.ty_to_value_string(ty.peel_refs()), + } + } else { + self.ty_to_value_string(rcvr_ty.peel_refs()) + }; + if let SelfSource::MethodCall(_) = source { + let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) + && let Some(assoc) = self.associated_value(*impl_did, item_name) + && assoc.kind == ty::AssocKind::Fn + { + let sig = self.tcx.fn_sig(assoc.def_id); + if let Some(first) = sig.inputs().skip_binder().get(0) { + if first.peel_refs() == rcvr_ty.peel_refs() { + None + } else { + Some(if first.is_region_ptr() { + if first.is_mutable_ptr() { "&mut " } else { "&" } + } else { + "" + }) + } + } else { + None + } + } else { + None + }; + let mut applicability = Applicability::MachineApplicable; + let args = if let Some((receiver, args)) = args { + // The first arg is the same kind as the receiver + let explicit_args = if first_arg.is_some() { + std::iter::once(receiver).chain(args.iter()).collect::>() + } else { + // There is no `Self` kind to infer the arguments from + if has_unsuggestable_args { + applicability = Applicability::HasPlaceholders; + } + args.iter().collect() + }; + format!( + "({}{})", + first_arg.unwrap_or(""), + explicit_args + .iter() + .map(|arg| self + .tcx + .sess + .source_map() + .span_to_snippet(arg.span) + .unwrap_or_else(|_| { + applicability = Applicability::HasPlaceholders; + "_".to_owned() + })) + .collect::>() + .join(", "), + ) + } else { + applicability = Applicability::HasPlaceholders; + "(...)".to_owned() + }; + err.span_suggestion( + sugg_span, + "use associated function syntax instead", + format!("{}::{}{}", ty_str, item_name, args), + applicability, + ); + } else { + err.help(&format!("try with `{}::{}`", ty_str, item_name,)); + } + } + /// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with /// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`. fn suggest_calling_field_as_fn( From 5497317aa542c490b1540edf5907dd29739bcecb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Nov 2022 19:18:38 +0000 Subject: [PATCH 17/20] Do autoderef to match impl against rcvr --- .../rustc_hir_typeck/src/method/suggest.rs | 92 +++++++++---------- .../suggest-assoc-fn-call-deref.fixed | 15 +++ .../suggest-assoc-fn-call-deref.rs | 15 +++ .../suggest-assoc-fn-call-deref.stderr | 19 ++++ 4 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs create mode 100644 src/test/ui/suggestions/suggest-assoc-fn-call-deref.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 821492179136b..edfe12963dc63 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -20,11 +20,10 @@ use rustc_infer::infer::{ }; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::traits::util::supertraits; +use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::print::with_crate_prefix; -use rustc_middle::ty::{ - self, DefIdTree, GenericArg, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable, -}; +use rustc_middle::ty::{self, DefIdTree, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable}; use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Symbol; @@ -1090,50 +1089,51 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // When the "method" is resolved through dereferencing, we really want the // original type that has the associated function for accurate suggestions. // (#61411) - let ty = self.tcx.type_of(*impl_did); - match (&ty.peel_refs().kind(), &rcvr_ty.peel_refs().kind()) { - (ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => { - // If there are any inferred arguments, (`{integer}`), we should replace - // them with underscores to allow the compiler to infer them - let infer_substs: Vec> = substs - .into_iter() - .map(|arg| { - if !arg.is_suggestable(self.tcx, true) { - has_unsuggestable_args = true; - match arg.unpack() { - GenericArgKind::Lifetime(_) => self - .next_region_var(RegionVariableOrigin::MiscVariable( - rustc_span::DUMMY_SP, - )) - .into(), - GenericArgKind::Type(_) => self - .next_ty_var(TypeVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: TypeVariableOriginKind::MiscVariable, - }) - .into(), - GenericArgKind::Const(arg) => self - .next_const_var( - arg.ty(), - ConstVariableOrigin { - span: rustc_span::DUMMY_SP, - kind: ConstVariableOriginKind::MiscVariable, - }, - ) - .into(), - } - } else { - arg - } - }) - .collect::>(); + let impl_ty = self.tcx.type_of(*impl_did); + let target_ty = self + .autoderef(sugg_span, rcvr_ty) + .find(|(rcvr_ty, _)| { + DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer } + .types_may_unify(*rcvr_ty, impl_ty) + }) + .map_or(impl_ty, |(ty, _)| ty) + .peel_refs(); + if let ty::Adt(def, substs) = target_ty.kind() { + // If there are any inferred arguments, (`{integer}`), we should replace + // them with underscores to allow the compiler to infer them + let infer_substs = self.tcx.mk_substs(substs.into_iter().map(|arg| { + if !arg.is_suggestable(self.tcx, true) { + has_unsuggestable_args = true; + match arg.unpack() { + GenericArgKind::Lifetime(_) => self + .next_region_var(RegionVariableOrigin::MiscVariable( + rustc_span::DUMMY_SP, + )) + .into(), + GenericArgKind::Type(_) => self + .next_ty_var(TypeVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: TypeVariableOriginKind::MiscVariable, + }) + .into(), + GenericArgKind::Const(arg) => self + .next_const_var( + arg.ty(), + ConstVariableOrigin { + span: rustc_span::DUMMY_SP, + kind: ConstVariableOriginKind::MiscVariable, + }, + ) + .into(), + } + } else { + arg + } + })); - self.tcx.value_path_str_with_substs( - def_actual.did(), - self.tcx.intern_substs(&infer_substs), - ) - } - _ => self.ty_to_value_string(ty.peel_refs()), + self.tcx.value_path_str_with_substs(def.did(), infer_substs) + } else { + self.ty_to_value_string(target_ty) } } else { self.ty_to_value_string(rcvr_ty.peel_refs()) 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 0000000000000..8d96cf590c398 --- /dev/null +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.fixed @@ -0,0 +1,15 @@ +// run-rustfix + +#![allow(unused)] + +struct Foo(T); + +impl Foo { + fn test() -> i32 { 1 } +} + +fn main() { + let x = Box::new(Foo(1i32)); + Foo::::test(); + //~^ ERROR no method named `test` found for struct `Box>` 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 0000000000000..186901f75a84b --- /dev/null +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-deref.rs @@ -0,0 +1,15 @@ +// run-rustfix + +#![allow(unused)] + +struct Foo(T); + +impl Foo { + fn test() -> i32 { 1 } +} + +fn main() { + let x = Box::new(Foo(1i32)); + x.test(); + //~^ ERROR no method named `test` found for struct `Box>` 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 0000000000000..00fb96f032668 --- /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>` 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::::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` + --> $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`. From 540e12f7daddec4581c5ff0f89c0172cc5005422 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 14 Nov 2022 19:29:17 +0000 Subject: [PATCH 18/20] Add regression test --- .../ui/suggestions/dont-suggest-ufcs-for-const.rs | 4 ++++ .../dont-suggest-ufcs-for-const.stderr | 15 +++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 src/test/ui/suggestions/dont-suggest-ufcs-for-const.rs create mode 100644 src/test/ui/suggestions/dont-suggest-ufcs-for-const.stderr 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 0000000000000..06cf243f1b4fa --- /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 0000000000000..04e0511d788ed --- /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`. From 7b00534952c9d2685a960e2d501cc4eefab6c075 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 14 Nov 2022 10:41:07 -0700 Subject: [PATCH 19/20] rustdoc: fix corner case in search keyboard commands --- src/librustdoc/html/static/js/search.js | 1 + src/test/rustdoc-gui/search-keyboard.goml | 28 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/test/rustdoc-gui/search-keyboard.goml diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index dd0531c5e70e4..4999bb3599487 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/test/rustdoc-gui/search-keyboard.goml b/src/test/rustdoc-gui/search-keyboard.goml new file mode 100644 index 0000000000000..be642fc49971f --- /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)" From 9214673331295f249c75d51f16f8b48bf6ca96c1 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 14 Nov 2022 22:42:57 +0000 Subject: [PATCH 20/20] Add test for #102154 --- src/test/rustdoc/issue-102154.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/test/rustdoc/issue-102154.rs diff --git a/src/test/rustdoc/issue-102154.rs b/src/test/rustdoc/issue-102154.rs new file mode 100644 index 0000000000000..b36f270806ff3 --- /dev/null +++ b/src/test/rustdoc/issue-102154.rs @@ -0,0 +1,13 @@ +trait A { + type B; +} +type MaybeBox = >>::B; +struct P { + t: MaybeBox

+} +impl A for P { + type B = N; +} +fn main() { + let t: MaybeBox

; +}