From 912963bd0856239828253af8d04e4f62e75cafd7 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 25 May 2020 13:53:02 +0100 Subject: [PATCH 01/92] Remove legacy InnoSetup GUI installer On Windows the InnoSetup installer was superseded by the MSI installer. It's no longer needed. --- .github/workflows/ci.yml | 9 -- src/bootstrap/dist.rs | 21 --- src/ci/azure-pipelines/steps/run.yml | 4 - src/ci/github-actions/ci.yml | 4 - src/ci/scripts/install-innosetup.sh | 18 --- src/etc/installer/exe/modpath.iss | 219 --------------------------- src/etc/installer/exe/rust.iss | 87 ----------- src/etc/installer/exe/upgrade.iss | 61 -------- 8 files changed, 423 deletions(-) delete mode 100755 src/ci/scripts/install-innosetup.sh delete mode 100644 src/etc/installer/exe/modpath.iss delete mode 100644 src/etc/installer/exe/rust.iss delete mode 100644 src/etc/installer/exe/upgrade.iss diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 291dbf603612a..6383cbdc139d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,9 +90,6 @@ jobs: - name: install WIX run: src/ci/scripts/install-wix.sh if: success() && !env.SKIP_JOB - - name: install InnoSetup - run: src/ci/scripts/install-innosetup.sh - if: success() && !env.SKIP_JOB - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh if: success() && !env.SKIP_JOB @@ -200,9 +197,6 @@ jobs: - name: install WIX run: src/ci/scripts/install-wix.sh if: success() && !env.SKIP_JOB - - name: install InnoSetup - run: src/ci/scripts/install-innosetup.sh - if: success() && !env.SKIP_JOB - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh if: success() && !env.SKIP_JOB @@ -552,9 +546,6 @@ jobs: - name: install WIX run: src/ci/scripts/install-wix.sh if: success() && !env.SKIP_JOB - - name: install InnoSetup - run: src/ci/scripts/install-innosetup.sh - if: success() && !env.SKIP_JOB - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh if: success() && !env.SKIP_JOB diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 5e966d7055bf3..b6c8e0652d1bd 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1859,28 +1859,7 @@ impl Step for Extended { prepare("rust-mingw"); } - builder.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644); - builder.install(&etc.join("exe/modpath.iss"), &exe, 0o644); - builder.install(&etc.join("exe/upgrade.iss"), &exe, 0o644); builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644); - builder.create(&exe.join("LICENSE.txt"), &license); - - // Generate exe installer - builder.info("building `exe` installer with `iscc`"); - let mut cmd = Command::new("iscc"); - cmd.arg("rust.iss").arg("/Q").current_dir(&exe); - if target.contains("windows-gnu") { - cmd.arg("/dMINGW"); - } - add_env(builder, &mut cmd, target); - let time = timeit(builder); - builder.run(&mut cmd); - drop(time); - builder.install( - &exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)), - &distdir(builder), - 0o755, - ); // Generate msi installer let wix = PathBuf::from(env::var_os("WIX").unwrap()); diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml index 85ff3e52a841d..5ceb280953a02 100644 --- a/src/ci/azure-pipelines/steps/run.yml +++ b/src/ci/azure-pipelines/steps/run.yml @@ -66,10 +66,6 @@ steps: displayName: Install wix condition: and(succeeded(), not(variables.SKIP_JOB)) -- bash: src/ci/scripts/install-innosetup.sh - displayName: Install InnoSetup - condition: and(succeeded(), not(variables.SKIP_JOB)) - - bash: src/ci/scripts/symlink-build-dir.sh displayName: Ensure the build happens on a partition with enough space condition: and(succeeded(), not(variables.SKIP_JOB)) diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 1c120f8163459..7a0cd7600598d 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -131,10 +131,6 @@ x--expand-yaml-anchors--remove: run: src/ci/scripts/install-wix.sh <<: *step - - name: install InnoSetup - run: src/ci/scripts/install-innosetup.sh - <<: *step - - name: ensure the build happens on a partition with enough space run: src/ci/scripts/symlink-build-dir.sh <<: *step diff --git a/src/ci/scripts/install-innosetup.sh b/src/ci/scripts/install-innosetup.sh deleted file mode 100755 index 04ca249777a11..0000000000000 --- a/src/ci/scripts/install-innosetup.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# We use InnoSetup and its `iscc` program to also create combined installers. -# Honestly at this point WIX above and `iscc` are just holdovers from -# oh-so-long-ago and are required for creating installers on Windows. I think -# one is MSI installers and one is EXE, but they're not used so frequently at -# this point anyway so perhaps it's a wash! - -set -euo pipefail -IFS=$'\n\t' - -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" - -if isWindows; then - curl.exe -o is-install.exe "${MIRRORS_BASE}/2017-08-22-is.exe" - cmd.exe //c "is-install.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-" - - ciCommandAddPath "C:\\Program Files (x86)\\Inno Setup 5" -fi diff --git a/src/etc/installer/exe/modpath.iss b/src/etc/installer/exe/modpath.iss deleted file mode 100644 index 2cfc8698c4b67..0000000000000 --- a/src/etc/installer/exe/modpath.iss +++ /dev/null @@ -1,219 +0,0 @@ -// ---------------------------------------------------------------------------- -// -// Inno Setup Ver: 5.4.2 -// Script Version: 1.4.1 -// Author: Jared Breland -// Homepage: http://www.legroom.net/software -// License: GNU Lesser General Public License (LGPL), version 3 -// http://www.gnu.org/licenses/lgpl.html -// -// Script Function: -// Allow modification of environmental path directly from Inno Setup installers -// -// Instructions: -// Copy modpath.iss to the same directory as your setup script -// -// Add this statement to your [Setup] section -// ChangesEnvironment=true -// -// Add this statement to your [Tasks] section -// You can change the Description or Flags -// You can change the Name, but it must match the ModPathName setting below -// Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked -// -// Add the following to the end of your [Code] section -// ModPathName defines the name of the task defined above -// ModPathType defines whether the 'user' or 'system' path will be modified; -// this will default to user if anything other than system is set -// setArrayLength must specify the total number of dirs to be added -// Result[0] contains first directory, Result[1] contains second, etc. -// const -// ModPathName = 'modifypath'; -// ModPathType = 'user'; -// -// function ModPathDir(): TArrayOfString; -// begin -// setArrayLength(Result, 1); -// Result[0] := ExpandConstant('{app}'); -// end; -// #include "modpath.iss" -// ---------------------------------------------------------------------------- - -procedure ModPath(); -var - oldpath: String; - newpath: String; - updatepath: Boolean; - pathArr: TArrayOfString; - aExecFile: String; - aExecArr: TArrayOfString; - i, d: Integer; - pathdir: TArrayOfString; - regroot: Integer; - regpath: String; - -begin - // Get constants from main script and adjust behavior accordingly - // ModPathType MUST be 'system' or 'user'; force 'user' if invalid - if ModPathType = 'system' then begin - regroot := HKEY_LOCAL_MACHINE; - regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'; - end else begin - regroot := HKEY_CURRENT_USER; - regpath := 'Environment'; - end; - - // Get array of new directories and act on each individually - pathdir := ModPathDir(); - for d := 0 to GetArrayLength(pathdir)-1 do begin - updatepath := true; - - // Modify WinNT path - if UsingWinNT() = true then begin - - // Get current path, split into an array - RegQueryStringValue(regroot, regpath, 'Path', oldpath); - oldpath := oldpath + ';'; - i := 0; - - while (Pos(';', oldpath) > 0) do begin - SetArrayLength(pathArr, i+1); - pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1); - oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath)); - i := i + 1; - - // Check if current directory matches app dir - if pathdir[d] = pathArr[i-1] then begin - // if uninstalling, remove dir from path - if IsUninstaller() = true then begin - continue; - // if installing, flag that dir already exists in path - end else begin - updatepath := false; - end; - end; - - // Add current directory to new path - if i = 1 then begin - newpath := pathArr[i-1]; - end else begin - newpath := newpath + ';' + pathArr[i-1]; - end; - end; - - // Append app dir to path if not already included - if (IsUninstaller() = false) AND (updatepath = true) then - newpath := newpath + ';' + pathdir[d]; - - // Write new path - RegWriteStringValue(regroot, regpath, 'Path', newpath); - - // Modify Win9x path - end else begin - - // Convert to shortened dirname - pathdir[d] := GetShortName(pathdir[d]); - - // If autoexec.bat exists, check if app dir already exists in path - aExecFile := 'C:\AUTOEXEC.BAT'; - if FileExists(aExecFile) then begin - LoadStringsFromFile(aExecFile, aExecArr); - for i := 0 to GetArrayLength(aExecArr)-1 do begin - if IsUninstaller() = false then begin - // If app dir already exists while installing, skip add - if (Pos(pathdir[d], aExecArr[i]) > 0) then - updatepath := false; - break; - end else begin - // If app dir exists and = what we originally set, then delete at uninstall - if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then - aExecArr[i] := ''; - end; - end; - end; - - // If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path - if (IsUninstaller() = false) AND (updatepath = true) then begin - SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True); - - // If uninstalling, write the full autoexec out - end else begin - SaveStringsToFile(aExecFile, aExecArr, False); - end; - end; - end; -end; - -// Split a string into an array using passed delimiter -procedure Explode(var Dest: TArrayOfString; Text: String; Separator: String); -var - i: Integer; -begin - i := 0; - repeat - SetArrayLength(Dest, i+1); - if Pos(Separator,Text) > 0 then begin - Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1); - Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text)); - i := i + 1; - end else begin - Dest[i] := Text; - Text := ''; - end; - until Length(Text)=0; -end; - - -procedure ModPathCurStepChanged(CurStep: TSetupStep); -var - taskname: String; -begin - taskname := ModPathName; - if CurStep = ssPostInstall then - if IsTaskSelected(taskname) then - ModPath(); -end; - -procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); -var - aSelectedTasks: TArrayOfString; - i: Integer; - taskname: String; - regpath: String; - regstring: String; - appid: String; -begin - // only run during actual uninstall - if CurUninstallStep = usUninstall then begin - // get list of selected tasks saved in registry at install time - appid := '{#emit SetupSetting("AppId")}'; - if appid = '' then appid := '{#emit SetupSetting("AppName")}'; - regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1'); - RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring); - if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring); - - // check each task; if matches modpath taskname, trigger patch removal - if regstring <> '' then begin - taskname := ModPathName; - Explode(aSelectedTasks, regstring, ','); - if GetArrayLength(aSelectedTasks) > 0 then begin - for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin - if comparetext(aSelectedTasks[i], taskname) = 0 then - ModPath(); - end; - end; - end; - end; -end; - -function NeedRestart(): Boolean; -var - taskname: String; -begin - taskname := ModPathName; - if IsTaskSelected(taskname) and not UsingWinNT() then begin - Result := True; - end else begin - Result := False; - end; -end; diff --git a/src/etc/installer/exe/rust.iss b/src/etc/installer/exe/rust.iss deleted file mode 100644 index 70648beac38b0..0000000000000 --- a/src/etc/installer/exe/rust.iss +++ /dev/null @@ -1,87 +0,0 @@ -#define CFG_RELEASE_NUM GetEnv("CFG_RELEASE_NUM") -#define CFG_RELEASE GetEnv("CFG_RELEASE") -#define CFG_PACKAGE_NAME GetEnv("CFG_PACKAGE_NAME") -#define CFG_BUILD GetEnv("CFG_BUILD") - -[Setup] - -SetupIconFile=rust-logo.ico -AppName=Rust -AppVersion={#CFG_RELEASE} -AppCopyright=Copyright (C) 2006-2014 Mozilla Foundation, MIT license -AppPublisher=Mozilla Foundation -AppPublisherURL=http://www.rust-lang.org -VersionInfoVersion={#CFG_RELEASE_NUM} -LicenseFile=LICENSE.txt - -PrivilegesRequired=lowest -DisableWelcomePage=true -DisableProgramGroupPage=true -DisableReadyPage=true -DisableStartupPrompt=true - -OutputDir=.\ -SourceDir=.\ -OutputBaseFilename={#CFG_PACKAGE_NAME}-{#CFG_BUILD} -DefaultDirName={sd}\Rust - -Compression=lzma2/normal -InternalCompressLevel=normal -SolidCompression=no - -ChangesEnvironment=true -ChangesAssociations=no -AllowUNCPath=false -AllowNoIcons=true -Uninstallable=yes - -[Tasks] -Name: modifypath; Description: &Add {app}\bin to your PATH (recommended) - -[Components] -Name: rust; Description: "Rust compiler and standard crates"; Types: full compact custom; Flags: fixed -#ifdef MINGW -Name: gcc; Description: "Linker and platform libraries"; Types: full -#endif -Name: docs; Description: "HTML documentation"; Types: full -Name: cargo; Description: "Cargo, the Rust package manager"; Types: full -Name: std; Description: "The Rust Standard Library"; Types: full -// tool-rls-start -Name: rls; Description: "RLS, the Rust Language Server" -// tool-rls-end - -[Files] -Source: "rustc/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rust -#ifdef MINGW -Source: "rust-mingw/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: gcc -#endif -Source: "rust-docs/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: docs -Source: "cargo/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: cargo -Source: "rust-std/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: std -// tool-rls-start -Source: "rls/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rls -Source: "rust-analysis/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rls -// tool-rls-end - -[Code] -const - ModPathName = 'modifypath'; - ModPathType = 'user'; - -function ModPathDir(): TArrayOfString; -begin - setArrayLength(Result, 1) - Result[0] := ExpandConstant('{app}\bin'); -end; - -#include "modpath.iss" -#include "upgrade.iss" - -// Both modpath.iss and upgrade.iss want to overload CurStepChanged. -// This version does the overload then delegates to each. - -procedure CurStepChanged(CurStep: TSetupStep); -begin - UpgradeCurStepChanged(CurStep); - ModPathCurStepChanged(CurStep); -end; diff --git a/src/etc/installer/exe/upgrade.iss b/src/etc/installer/exe/upgrade.iss deleted file mode 100644 index 29da7c333bb72..0000000000000 --- a/src/etc/installer/exe/upgrade.iss +++ /dev/null @@ -1,61 +0,0 @@ -// The following code taken from https://stackoverflow.com/questions/2000296/innosetup-how-to-automatically-uninstall-previous-installed-version -// It performs upgrades by running the uninstaller before the install - -///////////////////////////////////////////////////////////////////// -function GetUninstallString(): String; -var - sUnInstPath: String; - sUnInstallString: String; -begin - sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\Rust_is1'); - sUnInstallString := ''; - if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then - RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString); - Result := sUnInstallString; -end; - - -///////////////////////////////////////////////////////////////////// -function IsUpgrade(): Boolean; -begin - Result := (GetUninstallString() <> ''); -end; - - -///////////////////////////////////////////////////////////////////// -function UnInstallOldVersion(): Integer; -var - sUnInstallString: String; - iResultCode: Integer; -begin -// Return Values: -// 1 - uninstall string is empty -// 2 - error executing the UnInstallString -// 3 - successfully executed the UnInstallString - - // default return value - Result := 0; - - // get the uninstall string of the old app - sUnInstallString := GetUninstallString(); - if sUnInstallString <> '' then begin - sUnInstallString := RemoveQuotes(sUnInstallString); - if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then - Result := 3 - else - Result := 2; - end else - Result := 1; -end; - -///////////////////////////////////////////////////////////////////// -procedure UpgradeCurStepChanged(CurStep: TSetupStep); -begin - if (CurStep=ssInstall) then - begin - if (IsUpgrade()) then - begin - UnInstallOldVersion(); - end; - end; -end; From 8bc6b5b45c9f9710852e2b9c57eb3d44d08ad245 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Fri, 5 Jun 2020 16:37:27 +0200 Subject: [PATCH 02/92] stabilize leading_trailing_ones --- src/libcore/num/mod.rs | 24 ++++++++++++------------ src/libcore/tests/lib.rs | 1 - 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index c164e893b4fbf..0cbf3eb023041 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -457,13 +457,13 @@ $EndFeature, " Basic usage: ``` -", $Feature, "#![feature(leading_trailing_ones)] -let n = -1", stringify!($SelfT), "; +", $Feature, "let n = -1", stringify!($SelfT), "; assert_eq!(n.leading_ones(), ", stringify!($BITS), ");", $EndFeature, " ```"), - #[unstable(feature = "leading_trailing_ones", issue = "57969")] + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] #[inline] pub const fn leading_ones(self) -> u32 { (self as $UnsignedT).leading_ones() @@ -478,13 +478,13 @@ $EndFeature, " Basic usage: ``` -", $Feature, "#![feature(leading_trailing_ones)] -let n = 3", stringify!($SelfT), "; +", $Feature, "let n = 3", stringify!($SelfT), "; assert_eq!(n.trailing_ones(), 2);", $EndFeature, " ```"), - #[unstable(feature = "leading_trailing_ones", issue = "57969")] + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] #[inline] pub const fn trailing_ones(self) -> u32 { (self as $UnsignedT).trailing_ones() @@ -2695,12 +2695,12 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " Basic usage: ``` -", $Feature, "#![feature(leading_trailing_ones)] -let n = !(", stringify!($SelfT), "::MAX >> 2); +", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2); assert_eq!(n.leading_ones(), 2);", $EndFeature, " ```"), - #[unstable(feature = "leading_trailing_ones", issue = "57969")] + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] #[inline] pub const fn leading_ones(self) -> u32 { (!self).leading_zeros() @@ -2716,12 +2716,12 @@ of `self`. Basic usage: ``` -", $Feature, "#![feature(leading_trailing_ones)] -let n = 0b1010111", stringify!($SelfT), "; +", $Feature, "let n = 0b1010111", stringify!($SelfT), "; assert_eq!(n.trailing_ones(), 3);", $EndFeature, " ```"), - #[unstable(feature = "leading_trailing_ones", issue = "57969")] + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] #[inline] pub const fn trailing_ones(self) -> u32 { (!self).trailing_zeros() diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 37ebf4112808e..5ae20087e7ea5 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -40,7 +40,6 @@ #![feature(const_raw_ptr_deref)] #![feature(never_type)] #![feature(unwrap_infallible)] -#![feature(leading_trailing_ones)] #![feature(const_forget)] #![feature(option_unwrap_none)] #![feature(peekable_next_if)] From 144206e6d8c1ab4ffdbaf6d7b0f5a4201c0f2da4 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 13 Jun 2020 01:18:53 -0400 Subject: [PATCH 03/92] Don't implement Fn* traits for #[target_feature] functions --- .../traits/select/candidate_assembly.rs | 16 +++++++- .../rfc-2396-target_feature-11/fn-traits.rs | 24 ++++++++++++ .../fn-traits.stderr | 39 +++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs create mode 100644 src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/src/librustc_trait_selection/traits/select/candidate_assembly.rs index 9045451056b19..91c4d1d62aa70 100644 --- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs +++ b/src/librustc_trait_selection/traits/select/candidate_assembly.rs @@ -306,7 +306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.ambiguous = true; // Could wind up being a fn() type. } // Provide an impl, but only for suitable `fn` pointers. - ty::FnDef(..) | ty::FnPtr(_) => { + ty::FnPtr(_) => { if let ty::FnSig { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, @@ -317,6 +317,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(FnPointerCandidate); } } + // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). + ty::FnDef(def_id, _) => { + if let ty::FnSig { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + c_variadic: false, + .. + } = self_ty.fn_sig(self.tcx()).skip_binder() + { + if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() { + candidates.vec.push(FnPointerCandidate); + } + } + } _ => {} } diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs new file mode 100644 index 0000000000000..58070b69bc1f8 --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -0,0 +1,24 @@ +// only-x86_64 + +#![feature(target_feature_11)] + +#[target_feature(enable = "avx")] +fn foo() {} + +fn call(f: impl Fn()) { + f() +} + +fn call_mut(f: impl FnMut()) { + f() +} + +fn call_once(f: impl FnOnce()) { + f() +} + +fn main() { + call(foo); //~ ERROR expected a `std::ops::Fn<()>` closure, found `fn() {foo}` + call_mut(foo); //~ ERROR expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` + call_once(foo); //~ ERROR expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` +} diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr new file mode 100644 index 0000000000000..6dcf31b4c742a --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -0,0 +1,39 @@ +error[E0277]: expected a `std::ops::Fn<()>` closure, found `fn() {foo}` + --> $DIR/fn-traits.rs:21:10 + | +LL | fn call(f: impl Fn()) { + | ---- required by this bound in `call` +... +LL | call(foo); + | ^^^ expected an `Fn<()>` closure, found `fn() {foo}` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}` + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + +error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` + --> $DIR/fn-traits.rs:22:14 + | +LL | fn call_mut(f: impl FnMut()) { + | ------- required by this bound in `call_mut` +... +LL | call_mut(foo); + | ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` + | + = help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}` + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + +error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` + --> $DIR/fn-traits.rs:23:15 + | +LL | fn call_once(f: impl FnOnce()) { + | -------- required by this bound in `call_once` +... +LL | call_once(foo); + | ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` + | + = help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}` + = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. From c98b4c8fdde7812d7af5a060a1e22fd7e3775d3f Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 13 Jun 2020 11:03:31 -0400 Subject: [PATCH 04/92] Add error note when trying fn as Fn trait --- .../traits/error_reporting/mod.rs | 21 +++++++++ .../rfc-2396-target_feature-11/fn-traits.rs | 10 ++++ .../fn-traits.stderr | 47 +++++++++++++++++-- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 1b72a4bf84f19..39530853318e3 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -286,6 +286,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .starts_with("std::convert::From<"); let is_unsize = { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() }; + let is_fn_trait = [ + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + self.tcx.lang_items().fn_once_trait(), + ] + .contains(&Some(trait_ref.def_id())); + let is_safe_target_feature_fn = + if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind { + trait_ref.skip_binder().self_ty().fn_sig(self.tcx).unsafety() + == hir::Unsafety::Normal + && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() + } else { + false + }; let (message, note) = if is_try && is_from { ( Some(format!( @@ -427,6 +441,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); } + if is_fn_trait && is_safe_target_feature_fn { + err.note(&format!( + "`{}` has `#[target_feature]` and is unsafe to call", + trait_ref.skip_binder().self_ty(), + )); + } + // Try to report a help message if !trait_ref.has_infer_types_or_consts() && self.predicate_can_apply(obligation.param_env, trait_ref) diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs index 58070b69bc1f8..5c838fd719cd9 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -5,6 +5,9 @@ #[target_feature(enable = "avx")] fn foo() {} +#[target_feature(enable = "avx")] +unsafe fn foo_unsafe() {} + fn call(f: impl Fn()) { f() } @@ -21,4 +24,11 @@ fn main() { call(foo); //~ ERROR expected a `std::ops::Fn<()>` closure, found `fn() {foo}` call_mut(foo); //~ ERROR expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` call_once(foo); //~ ERROR expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` + + call(foo_unsafe); + //~^ ERROR expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + call_mut(foo_unsafe); + //~^ ERROR expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + call_once(foo_unsafe); + //~^ ERROR expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` } diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index 6dcf31b4c742a..3ae85af76d306 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -1,5 +1,5 @@ error[E0277]: expected a `std::ops::Fn<()>` closure, found `fn() {foo}` - --> $DIR/fn-traits.rs:21:10 + --> $DIR/fn-traits.rs:24:10 | LL | fn call(f: impl Fn()) { | ---- required by this bound in `call` @@ -9,9 +9,10 @@ LL | call(foo); | = help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` - --> $DIR/fn-traits.rs:22:14 + --> $DIR/fn-traits.rs:25:14 | LL | fn call_mut(f: impl FnMut()) { | ------- required by this bound in `call_mut` @@ -21,9 +22,10 @@ LL | call_mut(foo); | = help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` - --> $DIR/fn-traits.rs:23:15 + --> $DIR/fn-traits.rs:26:15 | LL | fn call_once(f: impl FnOnce()) { | -------- required by this bound in `call_once` @@ -33,7 +35,44 @@ LL | call_once(foo); | = help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } + = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call -error: aborting due to 3 previous errors +error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + --> $DIR/fn-traits.rs:28:10 + | +LL | fn call(f: impl Fn()) { + | ---- required by this bound in `call` +... +LL | call(foo_unsafe); + | ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + | + = help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + +error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + --> $DIR/fn-traits.rs:30:14 + | +LL | fn call_mut(f: impl FnMut()) { + | ------- required by this bound in `call_mut` +... +LL | call_mut(foo_unsafe); + | ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + | + = help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + +error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + --> $DIR/fn-traits.rs:32:15 + | +LL | fn call_once(f: impl FnOnce()) { + | -------- required by this bound in `call_once` +... +LL | call_once(foo_unsafe); + | ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + | + = help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. From 46bfc48272ba5312c439557e2901e1a4778e9487 Mon Sep 17 00:00:00 2001 From: pankajchaudhary5 Date: Sun, 10 May 2020 11:39:51 +0530 Subject: [PATCH 05/92] Added proper explanation of ErrorCode-E0687 --- src/librustc_error_codes/error_codes.rs | 2 +- src/librustc_error_codes/error_codes/E0687.md | 36 +++++++++++++++++++ src/test/ui/in-band-lifetimes/E0687.stderr | 1 + .../ui/in-band-lifetimes/E0687_where.stderr | 1 + 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/librustc_error_codes/error_codes/E0687.md diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 225ede851b4d9..c54cb81b00dbe 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -380,6 +380,7 @@ E0668: include_str!("./error_codes/E0668.md"), E0669: include_str!("./error_codes/E0669.md"), E0670: include_str!("./error_codes/E0670.md"), E0671: include_str!("./error_codes/E0671.md"), +E0687: include_str!("./error_codes/E0687.md"), E0689: include_str!("./error_codes/E0689.md"), E0690: include_str!("./error_codes/E0690.md"), E0691: include_str!("./error_codes/E0691.md"), @@ -599,7 +600,6 @@ E0751: include_str!("./error_codes/E0751.md"), E0640, // infer outlives requirements // E0645, // trait aliases not finished E0667, // `impl Trait` in projections - E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders // E0694, // an unknown tool name found in scoped attributes E0696, // `continue` pointing to a labeled block diff --git a/src/librustc_error_codes/error_codes/E0687.md b/src/librustc_error_codes/error_codes/E0687.md new file mode 100644 index 0000000000000..67b7db2d31fde --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0687.md @@ -0,0 +1,36 @@ +In-band lifetimes cannot be used in `fn`/`Fn` syntax. + +Erroneous code examples: + +```compile_fail,E0687 +#![feature(in_band_lifetimes)] + +fn foo(x: fn(&'a u32)) {} // error! + +fn bar(x: &Fn(&'a u32)) {} // error! + +fn baz(x: fn(&'a u32), y: &'a u32) {} // error! + +struct Foo<'a> { x: &'a u32 } + +impl Foo<'a> { + fn bar(&self, x: fn(&'a u32)) {} // error! +} +``` + +Lifetimes used in `fn` or `Fn` syntax must be explicitly +declared using `<...>` binders. For example: + +``` +fn foo<'a>(x: fn(&'a u32)) {} // ok! + +fn bar<'a>(x: &Fn(&'a u32)) {} // ok! + +fn baz<'a>(x: fn(&'a u32), y: &'a u32) {} // ok! + +struct Foo<'a> { x: &'a u32 } + +impl<'a> Foo<'a> { + fn bar(&self, x: fn(&'a u32)) {} // ok! +} +``` diff --git a/src/test/ui/in-band-lifetimes/E0687.stderr b/src/test/ui/in-band-lifetimes/E0687.stderr index e8e5100e00e07..7aea2f220466c 100644 --- a/src/test/ui/in-band-lifetimes/E0687.stderr +++ b/src/test/ui/in-band-lifetimes/E0687.stderr @@ -24,3 +24,4 @@ LL | fn bar(&self, x: fn(&'a u32)) {} error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0687`. diff --git a/src/test/ui/in-band-lifetimes/E0687_where.stderr b/src/test/ui/in-band-lifetimes/E0687_where.stderr index b422869c4db89..af0f9665f5d06 100644 --- a/src/test/ui/in-band-lifetimes/E0687_where.stderr +++ b/src/test/ui/in-band-lifetimes/E0687_where.stderr @@ -12,3 +12,4 @@ LL | fn baz(x: &impl Fn(&'a u32)) {} error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0687`. From 1d0378c454de72ddcfc08bcc105744923ef2d4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 18 Jun 2020 01:36:43 +0200 Subject: [PATCH 06/92] impl From for String This allows us to write fn char_to_string() -> String { 'a'.into() } which was not possible before. --- src/liballoc/string.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 0378ff5362a8b..cf86ba055b8af 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -2508,3 +2508,11 @@ impl DoubleEndedIterator for Drain<'_> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Drain<'_> {} + +#[stable(feature = "from_char_for_string", since = "1.46.0")] +impl From for String { + #[inline] + fn from(c: char) -> Self { + c.to_string() + } +} From 5c20ef433b48fce78c07208710bcc8b53965eeb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Wed, 17 Jun 2020 00:00:00 +0000 Subject: [PATCH 07/92] bootstrap: Configurable musl libdir Make it possible to customize the location of musl libdir using musl-libdir in config.toml, e.g., to use lib64 instead of lib. --- config.toml.example | 9 ++++++--- src/bootstrap/compile.rs | 6 +++--- src/bootstrap/config.rs | 3 +++ src/bootstrap/lib.rs | 9 +++++++++ src/bootstrap/sanity.rs | 8 ++++---- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/config.toml.example b/config.toml.example index d995554913f84..6214f2a68c596 100644 --- a/config.toml.example +++ b/config.toml.example @@ -359,7 +359,7 @@ # nightly features #channel = "dev" -# The root location of the MUSL installation directory. +# The root location of the musl installation directory. #musl-root = "..." # By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix @@ -502,12 +502,15 @@ # only use static libraries. If unset, the target's default linkage is used. #crt-static = false -# The root location of the MUSL installation directory. The library directory +# The root location of the musl installation directory. The library directory # will also need to contain libunwind.a for an unwinding implementation. Note -# that this option only makes sense for MUSL targets that produce statically +# that this option only makes sense for musl targets that produce statically # linked binaries #musl-root = "..." +# The full path to the musl libdir. +#musl-libdir = musl-root/lib + # The root location of the `wasm32-wasi` sysroot. #wasi-root = "..." diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index c9c75aed7b0fb..62bca0015c063 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -133,7 +133,7 @@ fn copy_third_party_objects( // To do that we have to distribute musl startup objects as a part of Rust toolchain // and link with them manually in the self-contained mode. if target.contains("musl") { - let srcdir = builder.musl_root(target).unwrap().join("lib"); + let srcdir = builder.musl_libdir(target).unwrap(); for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { copy_and_stamp(&srcdir, obj); } @@ -219,8 +219,8 @@ pub fn std_cargo(builder: &Builder<'_>, target: Interned, stage: u32, ca // Help the libc crate compile by assisting it in finding various // sysroot native libraries. if target.contains("musl") { - if let Some(p) = builder.musl_root(target) { - let root = format!("native={}/lib", p.to_str().unwrap()); + if let Some(p) = builder.musl_libdir(target) { + let root = format!("native={}", p.to_str().unwrap()); cargo.rustflag("-L").rustflag(&root); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 771f952abc013..ff545a6ddcf47 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -173,6 +173,7 @@ pub struct Target { pub ndk: Option, pub crt_static: Option, pub musl_root: Option, + pub musl_libdir: Option, pub wasi_root: Option, pub qemu_rootfs: Option, pub no_std: bool, @@ -363,6 +364,7 @@ struct TomlTarget { android_ndk: Option, crt_static: Option, musl_root: Option, + musl_libdir: Option, wasi_root: Option, qemu_rootfs: Option, no_std: Option, @@ -631,6 +633,7 @@ impl Config { target.linker = cfg.linker.clone().map(PathBuf::from); target.crt_static = cfg.crt_static; target.musl_root = cfg.musl_root.clone().map(PathBuf::from); + target.musl_libdir = cfg.musl_libdir.clone().map(PathBuf::from); target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8d8a036caef88..32f6e9605e765 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -877,6 +877,15 @@ impl Build { .map(|p| &**p) } + /// Returns the "musl libdir" for this `target`. + fn musl_libdir(&self, target: Interned) -> Option { + let t = self.config.target_config.get(&target)?; + if let libdir @ Some(_) = &t.musl_libdir { + return libdir.clone(); + } + self.musl_root(target).map(|root| root.join("lib")) + } + /// Returns the sysroot for the wasi target, if defined fn wasi_root(&self, target: Interned) -> Option<&Path> { self.config.target_config.get(&target).and_then(|t| t.wasi_root.as_ref()).map(|p| &**p) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 74b47d0772837..3301d41cfeefa 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -199,10 +199,10 @@ pub fn check(build: &mut Build) { let target = build.config.target_config.entry(target.clone()).or_default(); target.musl_root = Some("/usr".into()); } - match build.musl_root(*target) { - Some(root) => { - if fs::metadata(root.join("lib/libc.a")).is_err() { - panic!("couldn't find libc.a in musl dir: {}", root.join("lib").display()); + match build.musl_libdir(*target) { + Some(libdir) => { + if fs::metadata(libdir.join("libc.a")).is_err() { + panic!("couldn't find libc.a in musl libdir: {}", libdir.display()); } } None => panic!( From 2cde4932c7e8bd6000378af41029299ccf6eea69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Thu, 18 Jun 2020 11:19:03 +0200 Subject: [PATCH 08/92] add test for char into string --- src/liballoc/tests/string.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 9ea020d2d19f4..d38655af78cb7 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -714,3 +714,10 @@ fn test_try_reserve_exact() { } } } + +#[test] +fn test_from_char() { + assert_eq!(String::from('a'), 'a'.to_string()); + let s: String = 'x'.into(); + assert_eq!(s, 'x'.to_string()); +} From 886f81e1d0883f67fbc81b8ece61b1c33f6923d2 Mon Sep 17 00:00:00 2001 From: Anirban Date: Tue, 23 Jun 2020 16:11:13 +0530 Subject: [PATCH 09/92] Fix sentence structure Fixed grammar and sentence structure on appropriate instances. --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 42fc0a63c0ffb..e9273cb6db8d9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# The Rust Programming Language +# The Rust Programming Language This is the main source code repository for [Rust]. It contains the compiler, -standard library, and documentation. +standard library and documentation. [Rust]: https://www.rust-lang.org @@ -17,8 +17,8 @@ Read ["Installation"] from [The Book]. _Note: If you wish to contribute to the compiler, you should read [this chapter][rustcguidebuild] of the rustc-dev-guide instead of this section._ -The Rust build system has a Python script called `x.py` to bootstrap building -the compiler. More information about it may be found by running `./x.py --help` +The Rust build system has a Python script called `x.py` to bootstrap when building +the compiler. More information about it can be found by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html @@ -54,9 +54,9 @@ or reading the [rustc dev guide][rustcguidebuild]. $ cp config.toml.example config.toml ``` - It is recommended that if you plan to use the Rust build system to create - an installation (using `./x.py install`) that you set the `prefix` value - in the `[install]` section to a directory that you have write permissions. + It is recommended that you set the `prefix` value in the `[install]` + section to a directory that you have write permissions if you plan to use + the Rust build system to create an installation. (using `./x.py install`) Create install directory if you are not installing in default directory @@ -143,8 +143,8 @@ shell with: ``` Currently, building Rust only works with some known versions of Visual Studio. If -you have a more recent version installed the build system doesn't understand -then you may need to force rustbuild to use an older version. This can be done +you have a more recent version installed and the build system doesn't understand, +you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. ```batch From 50f20ec576ae72ceff6bf5a50c940cf574990e56 Mon Sep 17 00:00:00 2001 From: Dylan McKay Date: Wed, 24 Jun 2020 02:10:51 +1200 Subject: [PATCH 10/92] [AVR] Update the rust-lang/llvm-project submodule to include AVR fixes recently merged This commit updates rustc's LLVM submodule to include new AVR-specific fixes recently merged on the Rust LLVM 'rustc/10.0-2020-05-05' branch. All of these cherry-picked commits exist in upstream LLVM and were cherry-picked into Rust's LLVM fork in commit 6c040dd86ed. |- 6c040dd86ed Merge pull request #66 from dylanmckay/avr-pick-upstream-llvm-fixes |- 12dfdd3aed7 [AVR] Rewrite the function calling convention. |- 118ac53f12b [AVR] Don't adjust for instruction size |- bc27c282e13 [AVR] Fix miscompilation of zext + add |- cfbe205a7e8 [AVR] Remove faulty stack pushing behavior |- 143e1469e96 [AVR] Fix stack size in functions with a frame pointer |- 6b2445d841e [LLVM][AVR] Support for R_AVR_6 fixup |- 93ee4da19cf [AVR] Fix I/O instructions on XMEGA |- 962c2415ffb [AVR] Do not place functions in .progmem.data |- 65b8b170aef [AVR] Do not use divmod calls for bigger integers |- 93a3b595d1c [AVR] Generalize the previous interrupt bugfix to signal |- handlers too |- cc4286349b4 [AVR] Respect the 'interrupt' function attribute |- 954d0a92205 [AVR] Fix reads of uninitialized variables from constructor of AVRSubtarget |- 1c0ddae73c9 [AVR] Fix read of uninitialized variable AVRSubtarget:::ELFArch |- 0ed0823fe60 [AVR] Fix incorrect register state for LDRdPtr |- 96075fc433d [AVR] Don't adjust addresses by 2 for absolute values |- 6dfc55ba53b [AVR] Use correct register class for mul instructions These changes include both correctness fixes and LLVM assertion error fixes. Once all of these commits have been cherry-picked, all of the LLVM plumbing for rust-lang/master to compile the AVR blink program will be in place. Once this commit is merged, only PR rust-lang/rust#73270 will be blocking successful compilation and emission of the AVR LED blink program. --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index 0ddefeca92b2e..6c040dd86ed62 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 0ddefeca92b2e1835c80e9b01d9ecc7efc906b1c +Subproject commit 6c040dd86ed62d38e585279027486e6efc42fb36 From 0c88dd663a7095ccc405a2036047a90981137a51 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Tue, 23 Jun 2020 22:42:35 -0400 Subject: [PATCH 11/92] Update Box::from_raw example to generalize better I know very little about rust, so I saw this example and tried to generalize it by writing, ``` let layout = Layout::new::(); let new_obj = unsafe { let ptr = alloc(layout) as *mut T; *ptr = obj; Box::from_raw(ptr) }; ``` for some more complicated `T`, which ended up crashing with SIGSEGV, because it tried to `drop_in_place` the previous object in `ptr` which is of course garbage. I also added a comment that explains why `.write` is used, but I think adding that comment is optional and may be too verbose here. I do however think that changing this example is a good idea to suggest the correct generalization. `.write` is also used in most of the rest of the documentation here, even if the example is `i32`, so it would additionally be more consistent. --- src/liballoc/boxed.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d10cbf1afab30..02634825c2108 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -382,7 +382,10 @@ impl Box { /// /// unsafe { /// let ptr = alloc(Layout::new::()) as *mut i32; - /// *ptr = 5; + /// // In general .write is required to avoid attempting to destruct + /// // the (uninitialized) previous contents of `ptr`, though for this + /// // simple example `*ptr = 5` would have worked as well. + /// ptr.write(5); /// let x = Box::from_raw(ptr); /// } /// ``` From 3b5d7f8cf66c6704d36b021f7173241d6351ad32 Mon Sep 17 00:00:00 2001 From: Anirban Date: Wed, 24 Jun 2020 10:29:35 +0530 Subject: [PATCH 12/92] Minor correction to sentence structure --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e9273cb6db8d9..6258356fd4672 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # The Rust Programming Language This is the main source code repository for [Rust]. It contains the compiler, -standard library and documentation. +standard library, and documentation. [Rust]: https://www.rust-lang.org @@ -54,9 +54,8 @@ or reading the [rustc dev guide][rustcguidebuild]. $ cp config.toml.example config.toml ``` - It is recommended that you set the `prefix` value in the `[install]` - section to a directory that you have write permissions if you plan to use - the Rust build system to create an installation. (using `./x.py install`) + If you plan to use `x.py install` to create an installation, it is recommended + that you set the `prefix` value in the `[install]` section to a directory. Create install directory if you are not installing in default directory From d6cf8fc63ee24269bd4df20ad9fe19a219b5c9f5 Mon Sep 17 00:00:00 2001 From: Anirban Date: Wed, 24 Jun 2020 21:09:08 +0530 Subject: [PATCH 13/92] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6258356fd4672..f423d7527cc59 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# The Rust Programming Language + This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. @@ -17,9 +17,9 @@ Read ["Installation"] from [The Book]. _Note: If you wish to contribute to the compiler, you should read [this chapter][rustcguidebuild] of the rustc-dev-guide instead of this section._ -The Rust build system has a Python script called `x.py` to bootstrap when building -the compiler. More information about it can be found by running `./x.py --help` -or reading the [rustc dev guide][rustcguidebuild]. +The Rust build system uses a Python script called x.py to build the compiler, +which manages the bootstrapping process. More information about it can be found +by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html From 2bbc2b3de42f3b14ccc8b62c2acffc8840177777 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Thu, 25 Jun 2020 11:18:53 +0200 Subject: [PATCH 14/92] Document the static keyword --- src/libstd/keyword_docs.rs | 80 +++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index a4996d9eee810..746165beab8f5 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1030,9 +1030,85 @@ mod self_upper_keyword {} // /// A place that is valid for the duration of a program. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// A `static` item is similar to a [`const`] item in that it lives for the +/// entire duration of the program and need to have its type explicited, with a +/// `static` lifetime, outliving any other lifetime. Added to that, `static` +/// items represent a precise memory location. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// Static items do not call [`drop`] at the end of the program. +/// +/// There are two types of `static` items: those declared in association with +/// the [`mut`] keyword and those without. +/// +/// # Simple `static`s +/// +/// Non-[`mut`] `static` items that contain a type that is not interior mutable +/// may be placed in read-only memory. All access to a `static` item are +/// considered safe but some restrictions apply. See the [Reference] for more +/// information. +/// +/// ```rust +/// static FOO: [i32; 5] = [1, 2, 3, 4, 5]; +/// +/// let r1 = &FOO as *const _; +/// let r2 = &FOO as *const _; +/// // With a strictly read-only static, references will have the same adress +/// assert_eq!(r1, r2); +/// ``` +/// +/// # Mutable `static`s +/// +/// If a `static` item is declared with the [`mut`] keyword, then it is allowed +/// to be modified by the program. To make concurrency bugs hard to run into, +/// all access to a `static mut` require an [`unsafe`] block. Care should be +/// taken to ensure access (both read and write) are thread-safe. +/// +/// Despite their unsafety, mutable `static`s are very useful: they can be used +/// to represent global state shared by the whole program or be used in +/// [`extern`] blocks to bind to variables from C libraries. +/// +/// As global state: +/// +/// ```rust +/// # #![allow(unused_variables)] +/// # fn main() {} +/// # fn atomic_add(_: &mut u32, _: u32) -> u32 { 2 } +/// static mut LEVELS: u32 = 0; +/// +/// // This violates the idea of no shared state, and this doesn't internally +/// // protect against races, so this function is `unsafe` +/// unsafe fn bump_levels_unsafe1() -> u32 { +/// let ret = LEVELS; +/// LEVELS += 1; +/// return ret; +/// } +/// +/// // Assuming that we have an atomic_add function which returns the old value, +/// // this function is "safe" but the meaning of the return value may not be +/// // what callers expect, so it's still marked as `unsafe` +/// unsafe fn bump_levels_unsafe2() -> u32 { +/// return atomic_add(&mut LEVELS, 1); +/// } +/// ``` +/// +/// In an [`extern`] block: +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// extern "C" { +/// static mut ERROR_MESSAGE: *mut std::os::raw::c_char; +/// } +/// ``` +/// +/// Mutable `static`s, just like simple `static`s, have some restrictions that +/// apply to them. See the [Reference] for more information. +/// +/// [`const`]: keyword.const.html +/// [`extern`]: keyword.extern.html +/// [`mut`]: keyword.mut.html +/// [`unsafe`]: keyword.unsafe.html +/// [`drop`]: mem/fn.drop.html +/// [Reference]: ../reference/items/static-items.html#static-items mod static_keyword {} #[doc(keyword = "struct")] From 22fc18f1776ab05688d2f57ed92e14830a44d1ee Mon Sep 17 00:00:00 2001 From: Anirban Date: Thu, 25 Jun 2020 16:29:37 +0530 Subject: [PATCH 15/92] Commit suggestion Co-authored-by: Niko Matsakis --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f423d7527cc59..18fb19b85afaf 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Read ["Installation"] from [The Book]. _Note: If you wish to contribute to the compiler, you should read [this chapter][rustcguidebuild] of the rustc-dev-guide instead of this section._ -The Rust build system uses a Python script called x.py to build the compiler, +The Rust build system uses a Python script called `x.py` to build the compiler, which manages the bootstrapping process. More information about it can be found by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. From 8edcc6d00d329c4cbe51b483bb82a1b365a073b4 Mon Sep 17 00:00:00 2001 From: Anirban Date: Thu, 25 Jun 2020 16:32:54 +0530 Subject: [PATCH 16/92] Add alternate text for rust logo image --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 18fb19b85afaf..cad82f9c72ec9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - +The Rust Programming Language This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. From 3a1ac2823167e6254066758a7487ad384d32d7da Mon Sep 17 00:00:00 2001 From: Anirban Date: Thu, 25 Jun 2020 16:43:27 +0530 Subject: [PATCH 17/92] Added clickable-link Linked the logo/svg to https://www.rust-lang.org/ (change if required) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index cad82f9c72ec9..58b10f4e19b92 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ + The Rust Programming Language + This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. From 4c33b7c8d69648edcc7f4f3d2edbf96c00060d1e Mon Sep 17 00:00:00 2001 From: Anirban Date: Thu, 25 Jun 2020 19:33:19 +0530 Subject: [PATCH 18/92] Add responsiveness to logo Added responsiveness to image logo based on device width (set at 90% of device width, which can be changed as per requirement) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 58b10f4e19b92..c2ded10f05a36 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ - -The Rust Programming Language + +The Rust Programming Language This is the main source code repository for [Rust]. It contains the compiler, From b71a3e1e3a20e7db3b8167d19002c372ffe69c54 Mon Sep 17 00:00:00 2001 From: Tyler Ruckinger Date: Fri, 26 Jun 2020 00:43:34 -0400 Subject: [PATCH 19/92] Map ERROR_INVALID_PARAMETER to InvalidInput --- src/libstd/sys/windows/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 640c9f3636d4b..193ab5b47ef13 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -61,6 +61,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound, c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound, c::ERROR_NO_DATA => return ErrorKind::BrokenPipe, + c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput, c::ERROR_SEM_TIMEOUT | c::WAIT_TIMEOUT | c::ERROR_DRIVER_CANCEL_TIMEOUT From 31c6d5f35e3357d55411ba2057101a854d229d8a Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 16 Jun 2020 12:23:28 +0800 Subject: [PATCH 20/92] Add liballoc doc panic detail according to RawVec --- src/liballoc/raw_vec.rs | 12 +++--------- src/liballoc/vec.rs | 4 ++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 805dbfe277584..49dcbe706721a 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -80,9 +80,7 @@ impl RawVec { /// /// # Panics /// - /// * Panics if the requested capacity exceeds `usize::MAX` bytes. - /// * Panics on 32-bit platforms if the requested capacity exceeds - /// `isize::MAX` bytes. + /// Panics if the requested capacity exceeds `isize::MAX` bytes. /// /// # Aborts /// @@ -249,9 +247,7 @@ impl RawVec { /// /// # Panics /// - /// * Panics if the requested capacity exceeds `usize::MAX` bytes. - /// * Panics on 32-bit platforms if the requested capacity exceeds - /// `isize::MAX` bytes. + /// Panics if the new capacity exceeds `isize::MAX` bytes. /// /// # Aborts /// @@ -316,9 +312,7 @@ impl RawVec { /// /// # Panics /// - /// * Panics if the requested capacity exceeds `usize::MAX` bytes. - /// * Panics on 32-bit platforms if the requested capacity exceeds - /// `isize::MAX` bytes. + /// Panics if the new capacity exceeds `isize::MAX` bytes. /// /// # Aborts /// diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 06462fd96d9a9..861ee31c6944f 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -491,7 +491,7 @@ impl Vec { /// /// # Panics /// - /// Panics if the new capacity overflows `usize`. + /// Panics if the new capacity exceeds `isize::MAX` bytes. /// /// # Examples /// @@ -1188,7 +1188,7 @@ impl Vec { /// /// # Panics /// - /// Panics if the number of elements in the vector overflows a `usize`. + /// Panics if the new capacity exceeds `isize::MAX` bytes. /// /// # Examples /// From 15e81beb474235d100995f3bcc72d15086a8e29e Mon Sep 17 00:00:00 2001 From: root Date: Fri, 26 Jun 2020 19:07:36 +0000 Subject: [PATCH 21/92] moves terminator types to sub module --- src/librustc_middle/mir/mod.rs | 506 +-------------------- src/librustc_middle/mir/terminator/mod.rs | 507 ++++++++++++++++++++++ 2 files changed, 519 insertions(+), 494 deletions(-) create mode 100644 src/librustc_middle/mir/terminator/mod.rs diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index b3e410f362d68..ae516207fda15 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -21,7 +21,6 @@ use rustc_target::abi::VariantIdx; use polonius_engine::Atom; pub use rustc_ast::ast::Mutability; -use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::{dominators, Dominators}; use rustc_data_structures::graph::{self, GraphSuccessors}; @@ -47,6 +46,8 @@ pub mod mono; mod predecessors; mod query; pub mod tcx; +pub mod terminator; +pub use terminator::*; pub mod traversal; mod type_foldable; pub mod visit; @@ -298,7 +299,11 @@ impl<'tcx> Body<'tcx> { pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable() { None } else { Some(local) } + if self.local_decls[local].is_user_variable() { + None + } else { + Some(local) + } }) } @@ -1059,191 +1064,6 @@ pub struct BasicBlockData<'tcx> { pub is_cleanup: bool, } -#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] -pub struct Terminator<'tcx> { - pub source_info: SourceInfo, - pub kind: TerminatorKind<'tcx>, -} - -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)] -pub enum TerminatorKind<'tcx> { - /// Block should have one successor in the graph; we jump there. - Goto { target: BasicBlock }, - - /// Operand evaluates to an integer; jump depending on its value - /// to one of the targets, and otherwise fallback to `otherwise`. - SwitchInt { - /// The discriminant value being tested. - discr: Operand<'tcx>, - - /// The type of value being tested. - /// This is always the same as the type of `discr`. - /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing. - switch_ty: Ty<'tcx>, - - /// Possible values. The locations to branch to in each case - /// are found in the corresponding indices from the `targets` vector. - values: Cow<'tcx, [u128]>, - - /// Possible branch sites. The last element of this vector is used - /// for the otherwise branch, so targets.len() == values.len() + 1 - /// should hold. - // - // This invariant is quite non-obvious and also could be improved. - // One way to make this invariant is to have something like this instead: - // - // branches: Vec<(ConstInt, BasicBlock)>, - // otherwise: Option // exhaustive if None - // - // However we’ve decided to keep this as-is until we figure a case - // where some other approach seems to be strictly better than other. - targets: Vec, - }, - - /// Indicates that the landing pad is finished and unwinding should - /// continue. Emitted by `build::scope::diverge_cleanup`. - Resume, - - /// Indicates that the landing pad is finished and that the process - /// should abort. Used to prevent unwinding for foreign items. - Abort, - - /// Indicates a normal return. The return place should have - /// been filled in before this executes. This can occur multiple times - /// in different basic blocks. - Return, - - /// Indicates a terminator that can never be reached. - Unreachable, - - /// Drop the `Place`. - Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option }, - - /// Drop the `Place` and assign the new value over it. This ensures - /// that the assignment to `P` occurs *even if* the destructor for - /// place unwinds. Its semantics are best explained by the - /// elaboration: - /// - /// ``` - /// BB0 { - /// DropAndReplace(P <- V, goto BB1, unwind BB2) - /// } - /// ``` - /// - /// becomes - /// - /// ``` - /// BB0 { - /// Drop(P, goto BB1, unwind BB2) - /// } - /// BB1 { - /// // P is now uninitialized - /// P <- V - /// } - /// BB2 { - /// // P is now uninitialized -- its dtor panicked - /// P <- V - /// } - /// ``` - DropAndReplace { - place: Place<'tcx>, - value: Operand<'tcx>, - target: BasicBlock, - unwind: Option, - }, - - /// Block ends with a call of a converging function. - Call { - /// The function that’s being called. - func: Operand<'tcx>, - /// Arguments the function is called with. - /// These are owned by the callee, which is free to modify them. - /// This allows the memory occupied by "by-value" arguments to be - /// reused across function calls without duplicating the contents. - args: Vec>, - /// Destination for the return value. If some, the call is converging. - destination: Option<(Place<'tcx>, BasicBlock)>, - /// Cleanups to be done if the call unwinds. - cleanup: Option, - /// `true` if this is from a call in HIR rather than from an overloaded - /// operator. True for overloaded function call. - from_hir_call: bool, - /// This `Span` is the span of the function, without the dot and receiver - /// (e.g. `foo(a, b)` in `x.foo(a, b)` - fn_span: Span, - }, - - /// Jump to the target if the condition has the expected value, - /// otherwise panic with a message and a cleanup target. - Assert { - cond: Operand<'tcx>, - expected: bool, - msg: AssertMessage<'tcx>, - target: BasicBlock, - cleanup: Option, - }, - - /// A suspend point. - Yield { - /// The value to return. - value: Operand<'tcx>, - /// Where to resume to. - resume: BasicBlock, - /// The place to store the resume argument in. - resume_arg: Place<'tcx>, - /// Cleanup to be done if the generator is dropped at this suspend point. - drop: Option, - }, - - /// Indicates the end of the dropping of a generator. - GeneratorDrop, - - /// A block where control flow only ever takes one real path, but borrowck - /// needs to be more conservative. - FalseEdge { - /// The target normal control flow will take. - real_target: BasicBlock, - /// A block control flow could conceptually jump to, but won't in - /// practice. - imaginary_target: BasicBlock, - }, - /// A terminator for blocks that only take one path in reality, but where we - /// reserve the right to unwind in borrowck, even if it won't happen in practice. - /// This can arise in infinite loops with no function calls for example. - FalseUnwind { - /// The target normal control flow will take. - real_target: BasicBlock, - /// The imaginary cleanup block link. This particular path will never be taken - /// in practice, but in order to avoid fragility we want to always - /// consider it in borrowck. We don't want to accept programs which - /// pass borrowck only when `panic=abort` or some assertions are disabled - /// due to release vs. debug mode builds. This needs to be an `Option` because - /// of the `remove_noop_landing_pads` and `no_landing_pads` passes. - unwind: Option, - }, - - /// Block ends with an inline assembly block. This is a terminator since - /// inline assembly is allowed to diverge. - InlineAsm { - /// The template for the inline assembly, with placeholders. - template: &'tcx [InlineAsmTemplatePiece], - - /// The operands for the inline assembly, as `Operand`s or `Place`s. - operands: Vec>, - - /// Miscellaneous options for the inline assembly. - options: InlineAsmOptions, - - /// Source spans for each line of the inline assembly code. These are - /// used to map assembler errors back to the line in the source code. - line_spans: &'tcx [Span], - - /// Destination block after the inline assembly returns, unless it is - /// diverging (InlineAsmOptions::NORETURN). - destination: Option, - }, -} - /// Information about an assertion failure. #[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)] pub enum AssertKind { @@ -1292,149 +1112,6 @@ pub type Successors<'a> = pub type SuccessorsMut<'a> = iter::Chain, slice::IterMut<'a, BasicBlock>>; -impl<'tcx> Terminator<'tcx> { - pub fn successors(&self) -> Successors<'_> { - self.kind.successors() - } - - pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { - self.kind.successors_mut() - } - - pub fn unwind(&self) -> Option<&Option> { - self.kind.unwind() - } - - pub fn unwind_mut(&mut self) -> Option<&mut Option> { - self.kind.unwind_mut() - } -} - -impl<'tcx> TerminatorKind<'tcx> { - pub fn if_( - tcx: TyCtxt<'tcx>, - cond: Operand<'tcx>, - t: BasicBlock, - f: BasicBlock, - ) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &[u128] = &[0]; - TerminatorKind::SwitchInt { - discr: cond, - switch_ty: tcx.types.bool, - values: From::from(BOOL_SWITCH_FALSE), - targets: vec![f, t], - } - } - - pub fn successors(&self) -> Successors<'_> { - use self::TerminatorKind::*; - match *self { - Resume - | Abort - | GeneratorDrop - | Return - | Unreachable - | Call { destination: None, cleanup: None, .. } - | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]), - Goto { target: ref t } - | Call { destination: None, cleanup: Some(ref t), .. } - | Call { destination: Some((_, ref t)), cleanup: None, .. } - | Yield { resume: ref t, drop: None, .. } - | DropAndReplace { target: ref t, unwind: None, .. } - | Drop { target: ref t, unwind: None, .. } - | Assert { target: ref t, cleanup: None, .. } - | FalseUnwind { real_target: ref t, unwind: None } - | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]), - Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. } - | Yield { resume: ref t, drop: Some(ref u), .. } - | DropAndReplace { target: ref t, unwind: Some(ref u), .. } - | Drop { target: ref t, unwind: Some(ref u), .. } - | Assert { target: ref t, cleanup: Some(ref u), .. } - | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => { - Some(t).into_iter().chain(slice::from_ref(u)) - } - SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]), - FalseEdge { ref real_target, ref imaginary_target } => { - Some(real_target).into_iter().chain(slice::from_ref(imaginary_target)) - } - } - } - - pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { - use self::TerminatorKind::*; - match *self { - Resume - | Abort - | GeneratorDrop - | Return - | Unreachable - | Call { destination: None, cleanup: None, .. } - | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []), - Goto { target: ref mut t } - | Call { destination: None, cleanup: Some(ref mut t), .. } - | Call { destination: Some((_, ref mut t)), cleanup: None, .. } - | Yield { resume: ref mut t, drop: None, .. } - | DropAndReplace { target: ref mut t, unwind: None, .. } - | Drop { target: ref mut t, unwind: None, .. } - | Assert { target: ref mut t, cleanup: None, .. } - | FalseUnwind { real_target: ref mut t, unwind: None } - | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []), - Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. } - | Yield { resume: ref mut t, drop: Some(ref mut u), .. } - | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } - | Drop { target: ref mut t, unwind: Some(ref mut u), .. } - | Assert { target: ref mut t, cleanup: Some(ref mut u), .. } - | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { - Some(t).into_iter().chain(slice::from_mut(u)) - } - SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]), - FalseEdge { ref mut real_target, ref mut imaginary_target } => { - Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) - } - } - } - - pub fn unwind(&self) -> Option<&Option> { - match *self { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::GeneratorDrop - | TerminatorKind::Yield { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::InlineAsm { .. } => None, - TerminatorKind::Call { cleanup: ref unwind, .. } - | TerminatorKind::Assert { cleanup: ref unwind, .. } - | TerminatorKind::DropAndReplace { ref unwind, .. } - | TerminatorKind::Drop { ref unwind, .. } - | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind), - } - } - - pub fn unwind_mut(&mut self) -> Option<&mut Option> { - match *self { - TerminatorKind::Goto { .. } - | TerminatorKind::Resume - | TerminatorKind::Abort - | TerminatorKind::Return - | TerminatorKind::Unreachable - | TerminatorKind::GeneratorDrop - | TerminatorKind::Yield { .. } - | TerminatorKind::SwitchInt { .. } - | TerminatorKind::FalseEdge { .. } - | TerminatorKind::InlineAsm { .. } => None, - TerminatorKind::Call { cleanup: ref mut unwind, .. } - | TerminatorKind::Assert { cleanup: ref mut unwind, .. } - | TerminatorKind::DropAndReplace { ref mut unwind, .. } - | TerminatorKind::Drop { ref mut unwind, .. } - | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind), - } - } -} - impl<'tcx> BasicBlockData<'tcx> { pub fn new(terminator: Option>) -> BasicBlockData<'tcx> { BasicBlockData { statements: vec![], terminator, is_cleanup: false } @@ -1513,7 +1190,11 @@ impl<'tcx> BasicBlockData<'tcx> { } pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { - if index < self.statements.len() { &self.statements[index] } else { &self.terminator } + if index < self.statements.len() { + &self.statements[index] + } else { + &self.terminator + } } } @@ -1641,169 +1322,6 @@ impl fmt::Debug for AssertKind { } } -impl<'tcx> Debug for TerminatorKind<'tcx> { - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - self.fmt_head(fmt)?; - let successor_count = self.successors().count(); - let labels = self.fmt_successor_labels(); - assert_eq!(successor_count, labels.len()); - - match successor_count { - 0 => Ok(()), - - 1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()), - - _ => { - write!(fmt, " -> [")?; - for (i, target) in self.successors().enumerate() { - if i > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}: {:?}", labels[i], target)?; - } - write!(fmt, "]") - } - } - } -} - -impl<'tcx> TerminatorKind<'tcx> { - /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the - /// successor basic block, if any. The only information not included is the list of possible - /// successors, which may be rendered differently between the text and the graphviz format. - pub fn fmt_head(&self, fmt: &mut W) -> fmt::Result { - use self::TerminatorKind::*; - match self { - Goto { .. } => write!(fmt, "goto"), - SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr), - Return => write!(fmt, "return"), - GeneratorDrop => write!(fmt, "generator_drop"), - Resume => write!(fmt, "resume"), - Abort => write!(fmt, "abort"), - Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), - Unreachable => write!(fmt, "unreachable"), - Drop { place, .. } => write!(fmt, "drop({:?})", place), - DropAndReplace { place, value, .. } => { - write!(fmt, "replace({:?} <- {:?})", place, value) - } - Call { func, args, destination, .. } => { - if let Some((destination, _)) = destination { - write!(fmt, "{:?} = ", destination)?; - } - write!(fmt, "{:?}(", func)?; - for (index, arg) in args.iter().enumerate() { - if index > 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{:?}", arg)?; - } - write!(fmt, ")") - } - Assert { cond, expected, msg, .. } => { - write!(fmt, "assert(")?; - if !expected { - write!(fmt, "!")?; - } - write!(fmt, "{:?}, ", cond)?; - msg.fmt_assert_args(fmt)?; - write!(fmt, ")") - } - FalseEdge { .. } => write!(fmt, "falseEdge"), - FalseUnwind { .. } => write!(fmt, "falseUnwind"), - InlineAsm { template, ref operands, options, .. } => { - write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?; - for op in operands { - write!(fmt, ", ")?; - let print_late = |&late| if late { "late" } else { "" }; - match op { - InlineAsmOperand::In { reg, value } => { - write!(fmt, "in({}) {:?}", reg, value)?; - } - InlineAsmOperand::Out { reg, late, place: Some(place) } => { - write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?; - } - InlineAsmOperand::Out { reg, late, place: None } => { - write!(fmt, "{}out({}) _", print_late(late), reg)?; - } - InlineAsmOperand::InOut { - reg, - late, - in_value, - out_place: Some(out_place), - } => { - write!( - fmt, - "in{}out({}) {:?} => {:?}", - print_late(late), - reg, - in_value, - out_place - )?; - } - InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => { - write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?; - } - InlineAsmOperand::Const { value } => { - write!(fmt, "const {:?}", value)?; - } - InlineAsmOperand::SymFn { value } => { - write!(fmt, "sym_fn {:?}", value)?; - } - InlineAsmOperand::SymStatic { def_id } => { - write!(fmt, "sym_static {:?}", def_id)?; - } - } - } - write!(fmt, ", options({:?}))", options) - } - } - } - - /// Returns the list of labels for the edges to the successor basic blocks. - pub fn fmt_successor_labels(&self) -> Vec> { - use self::TerminatorKind::*; - match *self { - Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], - Goto { .. } => vec!["".into()], - SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| { - let param_env = ty::ParamEnv::empty(); - let switch_ty = tcx.lift(&switch_ty).unwrap(); - let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; - values - .iter() - .map(|&u| { - ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty) - .to_string() - .into() - }) - .chain(iter::once("otherwise".into())) - .collect() - }), - Call { destination: Some(_), cleanup: Some(_), .. } => { - vec!["return".into(), "unwind".into()] - } - Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()], - Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()], - Call { destination: None, cleanup: None, .. } => vec![], - Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], - Yield { drop: None, .. } => vec!["resume".into()], - DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { - vec!["return".into()] - } - DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => { - vec!["return".into(), "unwind".into()] - } - Assert { cleanup: None, .. } => vec!["".into()], - Assert { .. } => vec!["success".into(), "unwind".into()], - FalseEdge { .. } => vec!["real".into(), "imaginary".into()], - FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()], - FalseUnwind { unwind: None, .. } => vec!["real".into()], - InlineAsm { destination: Some(_), .. } => vec!["".into()], - InlineAsm { destination: None, .. } => vec![], - } - } -} - /////////////////////////////////////////////////////////////////////////// // Statements diff --git a/src/librustc_middle/mir/terminator/mod.rs b/src/librustc_middle/mir/terminator/mod.rs new file mode 100644 index 0000000000000..1f5041141d55b --- /dev/null +++ b/src/librustc_middle/mir/terminator/mod.rs @@ -0,0 +1,507 @@ +use crate::mir::interpret::Scalar; +use crate::ty::{self, Ty, TyCtxt}; +use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; + +use super::{ + AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors, + SuccessorsMut, +}; +pub use rustc_ast::ast::Mutability; +use rustc_macros::HashStable; +use rustc_span::Span; +use std::borrow::Cow; +use std::fmt::{self, Debug, Formatter, Write}; +use std::iter; +use std::slice; + +pub use super::query::*; + +#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)] +pub enum TerminatorKind<'tcx> { + /// Block should have one successor in the graph; we jump there. + Goto { target: BasicBlock }, + + /// Operand evaluates to an integer; jump depending on its value + /// to one of the targets, and otherwise fallback to `otherwise`. + SwitchInt { + /// The discriminant value being tested. + discr: Operand<'tcx>, + + /// The type of value being tested. + /// This is always the same as the type of `discr`. + /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing. + switch_ty: Ty<'tcx>, + + /// Possible values. The locations to branch to in each case + /// are found in the corresponding indices from the `targets` vector. + values: Cow<'tcx, [u128]>, + + /// Possible branch sites. The last element of this vector is used + /// for the otherwise branch, so targets.len() == values.len() + 1 + /// should hold. + // + // This invariant is quite non-obvious and also could be improved. + // One way to make this invariant is to have something like this instead: + // + // branches: Vec<(ConstInt, BasicBlock)>, + // otherwise: Option // exhaustive if None + // + // However we’ve decided to keep this as-is until we figure a case + // where some other approach seems to be strictly better than other. + targets: Vec, + }, + + /// Indicates that the landing pad is finished and unwinding should + /// continue. Emitted by `build::scope::diverge_cleanup`. + Resume, + + /// Indicates that the landing pad is finished and that the process + /// should abort. Used to prevent unwinding for foreign items. + Abort, + + /// Indicates a normal return. The return place should have + /// been filled in before this executes. This can occur multiple times + /// in different basic blocks. + Return, + + /// Indicates a terminator that can never be reached. + Unreachable, + + /// Drop the `Place`. + Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option }, + + /// Drop the `Place` and assign the new value over it. This ensures + /// that the assignment to `P` occurs *even if* the destructor for + /// place unwinds. Its semantics are best explained by the + /// elaboration: + /// + /// ``` + /// BB0 { + /// DropAndReplace(P <- V, goto BB1, unwind BB2) + /// } + /// ``` + /// + /// becomes + /// + /// ``` + /// BB0 { + /// Drop(P, goto BB1, unwind BB2) + /// } + /// BB1 { + /// // P is now uninitialized + /// P <- V + /// } + /// BB2 { + /// // P is now uninitialized -- its dtor panicked + /// P <- V + /// } + /// ``` + DropAndReplace { + place: Place<'tcx>, + value: Operand<'tcx>, + target: BasicBlock, + unwind: Option, + }, + + /// Block ends with a call of a converging function. + Call { + /// The function that’s being called. + func: Operand<'tcx>, + /// Arguments the function is called with. + /// These are owned by the callee, which is free to modify them. + /// This allows the memory occupied by "by-value" arguments to be + /// reused across function calls without duplicating the contents. + args: Vec>, + /// Destination for the return value. If some, the call is converging. + destination: Option<(Place<'tcx>, BasicBlock)>, + /// Cleanups to be done if the call unwinds. + cleanup: Option, + /// `true` if this is from a call in HIR rather than from an overloaded + /// operator. True for overloaded function call. + from_hir_call: bool, + /// This `Span` is the span of the function, without the dot and receiver + /// (e.g. `foo(a, b)` in `x.foo(a, b)` + fn_span: Span, + }, + + /// Jump to the target if the condition has the expected value, + /// otherwise panic with a message and a cleanup target. + Assert { + cond: Operand<'tcx>, + expected: bool, + msg: AssertMessage<'tcx>, + target: BasicBlock, + cleanup: Option, + }, + + /// A suspend point. + Yield { + /// The value to return. + value: Operand<'tcx>, + /// Where to resume to. + resume: BasicBlock, + /// The place to store the resume argument in. + resume_arg: Place<'tcx>, + /// Cleanup to be done if the generator is dropped at this suspend point. + drop: Option, + }, + + /// Indicates the end of the dropping of a generator. + GeneratorDrop, + + /// A block where control flow only ever takes one real path, but borrowck + /// needs to be more conservative. + FalseEdge { + /// The target normal control flow will take. + real_target: BasicBlock, + /// A block control flow could conceptually jump to, but won't in + /// practice. + imaginary_target: BasicBlock, + }, + /// A terminator for blocks that only take one path in reality, but where we + /// reserve the right to unwind in borrowck, even if it won't happen in practice. + /// This can arise in infinite loops with no function calls for example. + FalseUnwind { + /// The target normal control flow will take. + real_target: BasicBlock, + /// The imaginary cleanup block link. This particular path will never be taken + /// in practice, but in order to avoid fragility we want to always + /// consider it in borrowck. We don't want to accept programs which + /// pass borrowck only when `panic=abort` or some assertions are disabled + /// due to release vs. debug mode builds. This needs to be an `Option` because + /// of the `remove_noop_landing_pads` and `no_landing_pads` passes. + unwind: Option, + }, + + /// Block ends with an inline assembly block. This is a terminator since + /// inline assembly is allowed to diverge. + InlineAsm { + /// The template for the inline assembly, with placeholders. + template: &'tcx [InlineAsmTemplatePiece], + + /// The operands for the inline assembly, as `Operand`s or `Place`s. + operands: Vec>, + + /// Miscellaneous options for the inline assembly. + options: InlineAsmOptions, + + /// Source spans for each line of the inline assembly code. These are + /// used to map assembler errors back to the line in the source code. + line_spans: &'tcx [Span], + + /// Destination block after the inline assembly returns, unless it is + /// diverging (InlineAsmOptions::NORETURN). + destination: Option, + }, +} +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] +pub struct Terminator<'tcx> { + pub source_info: SourceInfo, + pub kind: TerminatorKind<'tcx>, +} + +impl<'tcx> Terminator<'tcx> { + pub fn successors(&self) -> Successors<'_> { + self.kind.successors() + } + + pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { + self.kind.successors_mut() + } + + pub fn unwind(&self) -> Option<&Option> { + self.kind.unwind() + } + + pub fn unwind_mut(&mut self) -> Option<&mut Option> { + self.kind.unwind_mut() + } +} + +impl<'tcx> TerminatorKind<'tcx> { + pub fn if_( + tcx: TyCtxt<'tcx>, + cond: Operand<'tcx>, + t: BasicBlock, + f: BasicBlock, + ) -> TerminatorKind<'tcx> { + static BOOL_SWITCH_FALSE: &[u128] = &[0]; + TerminatorKind::SwitchInt { + discr: cond, + switch_ty: tcx.types.bool, + values: From::from(BOOL_SWITCH_FALSE), + targets: vec![f, t], + } + } + + pub fn successors(&self) -> Successors<'_> { + use self::TerminatorKind::*; + match *self { + Resume + | Abort + | GeneratorDrop + | Return + | Unreachable + | Call { destination: None, cleanup: None, .. } + | InlineAsm { destination: None, .. } => None.into_iter().chain(&[]), + Goto { target: ref t } + | Call { destination: None, cleanup: Some(ref t), .. } + | Call { destination: Some((_, ref t)), cleanup: None, .. } + | Yield { resume: ref t, drop: None, .. } + | DropAndReplace { target: ref t, unwind: None, .. } + | Drop { target: ref t, unwind: None, .. } + | Assert { target: ref t, cleanup: None, .. } + | FalseUnwind { real_target: ref t, unwind: None } + | InlineAsm { destination: Some(ref t), .. } => Some(t).into_iter().chain(&[]), + Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. } + | Yield { resume: ref t, drop: Some(ref u), .. } + | DropAndReplace { target: ref t, unwind: Some(ref u), .. } + | Drop { target: ref t, unwind: Some(ref u), .. } + | Assert { target: ref t, cleanup: Some(ref u), .. } + | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => { + Some(t).into_iter().chain(slice::from_ref(u)) + } + SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]), + FalseEdge { ref real_target, ref imaginary_target } => { + Some(real_target).into_iter().chain(slice::from_ref(imaginary_target)) + } + } + } + + pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { + use self::TerminatorKind::*; + match *self { + Resume + | Abort + | GeneratorDrop + | Return + | Unreachable + | Call { destination: None, cleanup: None, .. } + | InlineAsm { destination: None, .. } => None.into_iter().chain(&mut []), + Goto { target: ref mut t } + | Call { destination: None, cleanup: Some(ref mut t), .. } + | Call { destination: Some((_, ref mut t)), cleanup: None, .. } + | Yield { resume: ref mut t, drop: None, .. } + | DropAndReplace { target: ref mut t, unwind: None, .. } + | Drop { target: ref mut t, unwind: None, .. } + | Assert { target: ref mut t, cleanup: None, .. } + | FalseUnwind { real_target: ref mut t, unwind: None } + | InlineAsm { destination: Some(ref mut t), .. } => Some(t).into_iter().chain(&mut []), + Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. } + | Yield { resume: ref mut t, drop: Some(ref mut u), .. } + | DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } + | Drop { target: ref mut t, unwind: Some(ref mut u), .. } + | Assert { target: ref mut t, cleanup: Some(ref mut u), .. } + | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { + Some(t).into_iter().chain(slice::from_mut(u)) + } + SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]), + FalseEdge { ref mut real_target, ref mut imaginary_target } => { + Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) + } + } + } + + pub fn unwind(&self) -> Option<&Option> { + match *self { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop + | TerminatorKind::Yield { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::InlineAsm { .. } => None, + TerminatorKind::Call { cleanup: ref unwind, .. } + | TerminatorKind::Assert { cleanup: ref unwind, .. } + | TerminatorKind::DropAndReplace { ref unwind, .. } + | TerminatorKind::Drop { ref unwind, .. } + | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind), + } + } + + pub fn unwind_mut(&mut self) -> Option<&mut Option> { + match *self { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop + | TerminatorKind::Yield { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::InlineAsm { .. } => None, + TerminatorKind::Call { cleanup: ref mut unwind, .. } + | TerminatorKind::Assert { cleanup: ref mut unwind, .. } + | TerminatorKind::DropAndReplace { ref mut unwind, .. } + | TerminatorKind::Drop { ref mut unwind, .. } + | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind), + } + } +} + +impl<'tcx> Debug for TerminatorKind<'tcx> { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + self.fmt_head(fmt)?; + let successor_count = self.successors().count(); + let labels = self.fmt_successor_labels(); + assert_eq!(successor_count, labels.len()); + + match successor_count { + 0 => Ok(()), + + 1 => write!(fmt, " -> {:?}", self.successors().next().unwrap()), + + _ => { + write!(fmt, " -> [")?; + for (i, target) in self.successors().enumerate() { + if i > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}: {:?}", labels[i], target)?; + } + write!(fmt, "]") + } + } + } +} + +impl<'tcx> TerminatorKind<'tcx> { + /// Writes the "head" part of the terminator; that is, its name and the data it uses to pick the + /// successor basic block, if any. The only information not included is the list of possible + /// successors, which may be rendered differently between the text and the graphviz format. + pub fn fmt_head(&self, fmt: &mut W) -> fmt::Result { + use self::TerminatorKind::*; + match self { + Goto { .. } => write!(fmt, "goto"), + SwitchInt { discr, .. } => write!(fmt, "switchInt({:?})", discr), + Return => write!(fmt, "return"), + GeneratorDrop => write!(fmt, "generator_drop"), + Resume => write!(fmt, "resume"), + Abort => write!(fmt, "abort"), + Yield { value, resume_arg, .. } => write!(fmt, "{:?} = yield({:?})", resume_arg, value), + Unreachable => write!(fmt, "unreachable"), + Drop { place, .. } => write!(fmt, "drop({:?})", place), + DropAndReplace { place, value, .. } => { + write!(fmt, "replace({:?} <- {:?})", place, value) + } + Call { func, args, destination, .. } => { + if let Some((destination, _)) = destination { + write!(fmt, "{:?} = ", destination)?; + } + write!(fmt, "{:?}(", func)?; + for (index, arg) in args.iter().enumerate() { + if index > 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{:?}", arg)?; + } + write!(fmt, ")") + } + Assert { cond, expected, msg, .. } => { + write!(fmt, "assert(")?; + if !expected { + write!(fmt, "!")?; + } + write!(fmt, "{:?}, ", cond)?; + msg.fmt_assert_args(fmt)?; + write!(fmt, ")") + } + FalseEdge { .. } => write!(fmt, "falseEdge"), + FalseUnwind { .. } => write!(fmt, "falseUnwind"), + InlineAsm { template, ref operands, options, .. } => { + write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?; + for op in operands { + write!(fmt, ", ")?; + let print_late = |&late| if late { "late" } else { "" }; + match op { + InlineAsmOperand::In { reg, value } => { + write!(fmt, "in({}) {:?}", reg, value)?; + } + InlineAsmOperand::Out { reg, late, place: Some(place) } => { + write!(fmt, "{}out({}) {:?}", print_late(late), reg, place)?; + } + InlineAsmOperand::Out { reg, late, place: None } => { + write!(fmt, "{}out({}) _", print_late(late), reg)?; + } + InlineAsmOperand::InOut { + reg, + late, + in_value, + out_place: Some(out_place), + } => { + write!( + fmt, + "in{}out({}) {:?} => {:?}", + print_late(late), + reg, + in_value, + out_place + )?; + } + InlineAsmOperand::InOut { reg, late, in_value, out_place: None } => { + write!(fmt, "in{}out({}) {:?} => _", print_late(late), reg, in_value)?; + } + InlineAsmOperand::Const { value } => { + write!(fmt, "const {:?}", value)?; + } + InlineAsmOperand::SymFn { value } => { + write!(fmt, "sym_fn {:?}", value)?; + } + InlineAsmOperand::SymStatic { def_id } => { + write!(fmt, "sym_static {:?}", def_id)?; + } + } + } + write!(fmt, ", options({:?}))", options) + } + } + } + + /// Returns the list of labels for the edges to the successor basic blocks. + pub fn fmt_successor_labels(&self) -> Vec> { + use self::TerminatorKind::*; + match *self { + Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], + Goto { .. } => vec!["".into()], + SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| { + let param_env = ty::ParamEnv::empty(); + let switch_ty = tcx.lift(&switch_ty).unwrap(); + let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; + values + .iter() + .map(|&u| { + ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty) + .to_string() + .into() + }) + .chain(iter::once("otherwise".into())) + .collect() + }), + Call { destination: Some(_), cleanup: Some(_), .. } => { + vec!["return".into(), "unwind".into()] + } + Call { destination: Some(_), cleanup: None, .. } => vec!["return".into()], + Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into()], + Call { destination: None, cleanup: None, .. } => vec![], + Yield { drop: Some(_), .. } => vec!["resume".into(), "drop".into()], + Yield { drop: None, .. } => vec!["resume".into()], + DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { + vec!["return".into()] + } + DropAndReplace { unwind: Some(_), .. } | Drop { unwind: Some(_), .. } => { + vec!["return".into(), "unwind".into()] + } + Assert { cleanup: None, .. } => vec!["".into()], + Assert { .. } => vec!["success".into(), "unwind".into()], + FalseEdge { .. } => vec!["real".into(), "imaginary".into()], + FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()], + FalseUnwind { unwind: None, .. } => vec!["real".into()], + InlineAsm { destination: Some(_), .. } => vec!["".into()], + InlineAsm { destination: None, .. } => vec![], + } + } +} From cf398a33ebff501a01c9c91fe5615992c936d292 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 26 Jun 2020 19:40:09 +0000 Subject: [PATCH 22/92] removes unnecessary tidy ignore --- src/librustc_middle/mir/mod.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index ae516207fda15..472cedeaa73aa 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -2,8 +2,6 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html -// ignore-tidy-filelength - use crate::mir::interpret::{GlobalAlloc, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; @@ -299,11 +297,7 @@ impl<'tcx> Body<'tcx> { pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable() { - None - } else { - Some(local) - } + if self.local_decls[local].is_user_variable() { None } else { Some(local) } }) } @@ -1190,11 +1184,7 @@ impl<'tcx> BasicBlockData<'tcx> { } pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> { - if index < self.statements.len() { - &self.statements[index] - } else { - &self.terminator - } + if index < self.statements.len() { &self.statements[index] } else { &self.terminator } } } From 224bc052564117abfb8716772779ade221133395 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 26 Jun 2020 21:05:39 +0100 Subject: [PATCH 23/92] Fix allow_internal_unstable with rustc_const_unstable --- .../transform/check_consts/validation.rs | 7 +++++-- .../transform/qualify_min_const_fn.rs | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index d263bf12e8868..80257260f0183 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -548,9 +548,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if is_lang_panic_fn(self.tcx, def_id) { self.check_op(ops::Panic); } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) { - // Exempt unstable const fns inside of macros with + // Exempt unstable const fns inside of macros or functions with // `#[allow_internal_unstable]`. - if !self.span.allows_unstable(feature) { + use crate::transform::qualify_min_const_fn::feature_allowed; + if !self.span.allows_unstable(feature) + && !feature_allowed(self.tcx, self.def_id, feature) + { self.check_op(ops::FnCallUnstable(def_id, feature)); } } else { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index caf6c7715a9e1..6f252ad4ed535 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -315,7 +315,7 @@ fn check_place( } /// Returns `true` if the given feature gate is allowed within the function with the given `DefId`. -fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { +pub fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { // All features require that the corresponding gate be enabled, // even if the function has `#[allow_internal_unstable(the_gate)]`. if !tcx.features().enabled(feature_gate) { @@ -377,8 +377,16 @@ fn check_terminator( fn_span: _, } => { let fn_ty = func.ty(body, tcx); - if let ty::FnDef(def_id, _) = fn_ty.kind { - if !crate::const_eval::is_min_const_fn(tcx, def_id) { + if let ty::FnDef(fn_def_id, _) = fn_ty.kind { + // Allow unstable const if we opt in by using #[allow_internal_unstable] + // on function or macro declaration. + if !crate::const_eval::is_min_const_fn(tcx, fn_def_id) + && !crate::const_eval::is_unstable_const_fn(tcx, fn_def_id) + .map(|feature| { + span.allows_unstable(feature) || feature_allowed(tcx, def_id, feature) + }) + .unwrap_or(false) + { return Err(( span, format!( @@ -390,10 +398,10 @@ fn check_terminator( )); } - check_operand(tcx, func, span, def_id, body)?; + check_operand(tcx, func, span, fn_def_id, body)?; for arg in args { - check_operand(tcx, arg, span, def_id, body)?; + check_operand(tcx, arg, span, fn_def_id, body)?; } Ok(()) } else { From fc239e82fe1ef91632dfa858487d89141aaab7a7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 26 Jun 2020 13:19:50 +0100 Subject: [PATCH 24/92] Make `likely` and `unlikely` const They are gated by internal feature gate const_likely --- src/libcore/intrinsics.rs | 2 ++ src/libcore/lib.rs | 1 + src/librustc_mir/interpret/intrinsics.rs | 5 +++++ src/librustc_span/symbol.rs | 2 ++ 4 files changed, 10 insertions(+) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 2298958b88101..da174299fb9af 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -952,6 +952,7 @@ extern "rust-intrinsic" { /// Any use other than with `if` statements will probably not have an effect. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_likely", issue = "none")] pub fn likely(b: bool) -> bool; /// Hints to the compiler that branch condition is likely to be false. @@ -960,6 +961,7 @@ extern "rust-intrinsic" { /// Any use other than with `if` statements will probably not have an effect. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_likely", issue = "none")] pub fn unlikely(b: bool) -> bool; /// Executes a breakpoint trap, for inspection by a debugger. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4eb2fdbd07868..412d323b283a3 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -92,6 +92,7 @@ #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_type_name)] +#![feature(const_likely)] #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 6ac1e6be03674..52cb700c3d58f 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -399,6 +399,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ); self.copy_op(self.operand_index(args[0], index)?, dest)?; } + sym::likely | sym::unlikely => { + // These just return their argument + let a = self.read_immediate(args[0])?; + self.write_immediate(*a, dest)?; + } // FIXME(#73156): Handle source code coverage in const eval sym::count_code_region => (), _ => return Ok(false), diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index fa1368b104c7e..3e62486feb95e 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -427,6 +427,7 @@ symbols! { lhs, lib, lifetime, + likely, line, link, linkage, @@ -813,6 +814,7 @@ symbols! { underscore_lifetimes, uniform_paths, universal_impl_trait, + unlikely, unmarked_api, unreachable_code, unrestricted_attribute_tokens, From 779b05d16a38fec347a874210e2ae54579a8f5c1 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 26 Jun 2020 23:33:35 +0100 Subject: [PATCH 25/92] Fix ICE for lib features --- .../transform/check_consts/validation.rs | 4 +-- .../transform/qualify_min_const_fn.rs | 25 +++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 80257260f0183..bd9d33e67f8fb 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -550,9 +550,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) { // Exempt unstable const fns inside of macros or functions with // `#[allow_internal_unstable]`. - use crate::transform::qualify_min_const_fn::feature_allowed; + use crate::transform::qualify_min_const_fn::lib_feature_allowed; if !self.span.allows_unstable(feature) - && !feature_allowed(self.tcx, self.def_id, feature) + && !lib_feature_allowed(self.tcx, self.def_id, feature) { self.check_op(ops::FnCallUnstable(def_id, feature)); } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 6f252ad4ed535..7c54acf2163cc 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -315,7 +315,7 @@ fn check_place( } /// Returns `true` if the given feature gate is allowed within the function with the given `DefId`. -pub fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { +fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { // All features require that the corresponding gate be enabled, // even if the function has `#[allow_internal_unstable(the_gate)]`. if !tcx.features().enabled(feature_gate) { @@ -334,6 +334,26 @@ pub fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) } +/// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`. +pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { + // All features require that the corresponding gate be enabled, + // even if the function has `#[allow_internal_unstable(the_gate)]`. + if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_gate) { + return false; + } + + // If this crate is not using stability attributes, or this function is not claiming to be a + // stable `const fn`, that is all that is required. + if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { + return true; + } + + // However, we cannot allow stable `const fn`s to use unstable features without an explicit + // opt-in via `allow_internal_unstable`. + attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic()) + .map_or(false, |mut features| features.any(|name| name == feature_gate)) +} + fn check_terminator( tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, @@ -383,7 +403,8 @@ fn check_terminator( if !crate::const_eval::is_min_const_fn(tcx, fn_def_id) && !crate::const_eval::is_unstable_const_fn(tcx, fn_def_id) .map(|feature| { - span.allows_unstable(feature) || feature_allowed(tcx, def_id, feature) + span.allows_unstable(feature) + || lib_feature_allowed(tcx, def_id, feature) }) .unwrap_or(false) { From 79a42e37084d0fc584c9f312c2a355104a113889 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 20 Jun 2020 23:26:24 +0300 Subject: [PATCH 26/92] linker: Create GNU_EH_FRAME header by default when producing ELFs --- src/librustc_codegen_ssa/back/link.rs | 3 +++ src/librustc_codegen_ssa/back/linker.rs | 14 ++++++++++++++ src/librustc_target/spec/cloudabi_base.rs | 1 - src/librustc_target/spec/fuchsia_base.rs | 1 - src/librustc_target/spec/linux_musl_base.rs | 8 +------- src/librustc_target/spec/mipsel_sony_psp.rs | 5 +---- .../spec/x86_64_fortanix_unknown_sgx.rs | 1 - 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index a34029410784a..3adaa07db91b0 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -1597,6 +1597,9 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix)); } + // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER + cmd.add_eh_frame_header(); + // NO-OPT-OUT, OBJECT-FILES-NO if crt_objects_fallback { cmd.no_crt_objects(); diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index d6ef94bfd1727..54f55c806d035 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -129,6 +129,7 @@ pub trait Linker { fn group_start(&mut self); fn group_end(&mut self); fn linker_plugin_lto(&mut self); + fn add_eh_frame_header(&mut self) {} fn finalize(&mut self); } @@ -615,6 +616,19 @@ impl<'a> Linker for GccLinker<'a> { } } } + + // Add the `GNU_EH_FRAME` program header which is required to locate unwinding information. + // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't, + // so we just always add it. + fn add_eh_frame_header(&mut self) { + // The condition here is "uses ELF" basically. + if !self.sess.target.target.options.is_like_osx + && !self.sess.target.target.options.is_like_windows + && self.sess.target.target.target_os != "uefi" + { + self.linker_arg("--eh-frame-hdr"); + } + } } pub struct MsvcLinker<'a> { diff --git a/src/librustc_target/spec/cloudabi_base.rs b/src/librustc_target/spec/cloudabi_base.rs index 3659c9ecdfca6..39039435f5815 100644 --- a/src/librustc_target/spec/cloudabi_base.rs +++ b/src/librustc_target/spec/cloudabi_base.rs @@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions { vec![ "-Wl,-Bstatic".to_string(), "-Wl,--no-dynamic-linker".to_string(), - "-Wl,--eh-frame-hdr".to_string(), "-Wl,--gc-sections".to_string(), ], ); diff --git a/src/librustc_target/spec/fuchsia_base.rs b/src/librustc_target/spec/fuchsia_base.rs index dd55788b664ea..6f432dc11718d 100644 --- a/src/librustc_target/spec/fuchsia_base.rs +++ b/src/librustc_target/spec/fuchsia_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { LinkerFlavor::Lld(LldFlavor::Ld), vec![ "--build-id".to_string(), - "--eh-frame-hdr".to_string(), "--hash-style=gnu".to_string(), "-z".to_string(), "max-page-size=4096".to_string(), diff --git a/src/librustc_target/spec/linux_musl_base.rs b/src/librustc_target/spec/linux_musl_base.rs index 0fdd876080677..b90e91d2901a8 100644 --- a/src/librustc_target/spec/linux_musl_base.rs +++ b/src/librustc_target/spec/linux_musl_base.rs @@ -1,15 +1,9 @@ use crate::spec::crt_objects::{self, CrtObjectsFallback}; -use crate::spec::{LinkerFlavor, TargetOptions}; +use crate::spec::TargetOptions; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); - // At least when this was tested, the linker would not add the - // `GNU_EH_FRAME` program header to executables generated, which is required - // when unwinding to locate the unwinding information. I'm not sure why this - // argument is *not* necessary for normal builds, but it can't hurt! - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string()); - base.pre_link_objects_fallback = crt_objects::pre_musl_fallback(); base.post_link_objects_fallback = crt_objects::post_musl_fallback(); base.crt_objects_fallback = Some(CrtObjectsFallback::Musl); diff --git a/src/librustc_target/spec/mipsel_sony_psp.rs b/src/librustc_target/spec/mipsel_sony_psp.rs index 0c74454d0c5fe..b3bda97c8a570 100644 --- a/src/librustc_target/spec/mipsel_sony_psp.rs +++ b/src/librustc_target/spec/mipsel_sony_psp.rs @@ -6,10 +6,7 @@ const LINKER_SCRIPT: &str = include_str!("./mipsel_sony_psp_linker_script.ld"); pub fn target() -> TargetResult { let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( - LinkerFlavor::Lld(LldFlavor::Ld), - vec!["--eh-frame-hdr".to_string(), "--emit-relocs".to_string()], - ); + pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["--emit-relocs".to_string()]); Ok(Target { llvm_target: "mipsel-sony-psp".to_string(), diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index d01545619c8fa..3b5233a3e677d 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -5,7 +5,6 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Result { const PRE_LINK_ARGS: &[&str] = &[ "--as-needed", - "--eh-frame-hdr", "-z", "noexecstack", "-e", From 765bd47fa0f0e0d5d893283a94c76e2b1009d680 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 27 Jun 2020 11:35:12 -0400 Subject: [PATCH 27/92] Recover extra trailing angle brackets in struct definition This commit applies the existing 'extra angle bracket recovery' logic when parsing fields in struct definitions. This allows us to continue parsing the struct's fields, avoiding spurious 'missing field' errors in code that tries to use the struct. --- src/librustc_parse/parser/diagnostics.rs | 19 ++++++++---- src/librustc_parse/parser/expr.rs | 2 +- src/librustc_parse/parser/item.rs | 29 ++++++++++++++++++- src/librustc_parse/parser/path.rs | 2 +- .../recover-field-extra-angle-brackets.rs | 14 +++++++++ .../recover-field-extra-angle-brackets.stderr | 8 +++++ 6 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/parser/recover-field-extra-angle-brackets.rs create mode 100644 src/test/ui/parser/recover-field-extra-angle-brackets.stderr diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index fc9ffc3092447..4b060bf108f4e 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -376,7 +376,14 @@ impl<'a> Parser<'a> { /// let _ = vec![1, 2, 3].into_iter().collect::>>>(); /// ^^ help: remove extra angle brackets /// ``` - pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) { + /// + /// If `true` is returned, then trailing brackets were recovered, tokens were consumed + /// up until one of the tokens in 'end' was encountered, and an error was emitted. + pub(super) fn check_trailing_angle_brackets( + &mut self, + segment: &PathSegment, + end: &[&TokenKind], + ) -> bool { // This function is intended to be invoked after parsing a path segment where there are two // cases: // @@ -409,7 +416,7 @@ impl<'a> Parser<'a> { parsed_angle_bracket_args, ); if !parsed_angle_bracket_args { - return; + return false; } // Keep the span at the start so we can highlight the sequence of `>` characters to be @@ -447,18 +454,18 @@ impl<'a> Parser<'a> { number_of_gt, number_of_shr, ); if number_of_gt < 1 && number_of_shr < 1 { - return; + return false; } // Finally, double check that we have our end token as otherwise this is the // second case. if self.look_ahead(position, |t| { trace!("check_trailing_angle_brackets: t={:?}", t); - *t == end + end.contains(&&t.kind) }) { // Eat from where we started until the end token so that parsing can continue // as if we didn't have those extra angle brackets. - self.eat_to_tokens(&[&end]); + self.eat_to_tokens(end); let span = lo.until(self.token.span); let total_num_of_gt = number_of_gt + number_of_shr * 2; @@ -473,7 +480,9 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ) .emit(); + return true; } + false } /// Check to see if a pair of chained operators looks like an attempt at chained comparison, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 2745b18a8cd51..fb38fdc26c782 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -867,7 +867,7 @@ impl<'a> Parser<'a> { let fn_span_lo = self.token.span; let segment = self.parse_path_segment(PathStyle::Expr)?; - self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren)); + self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]); if self.check(&token::OpenDelim(token::Paren)) { // Method call `expr.f()` diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 10df16964da08..fa6264c98e4f0 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind, use rustc_ast::ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; use rustc_ast::ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData}; -use rustc_ast::ast::{FnHeader, ForeignItem, PathSegment, Visibility, VisibilityKind}; +use rustc_ast::ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::ast::{MacArgs, MacCall, MacDelimiter}; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; @@ -1262,6 +1262,25 @@ impl<'a> Parser<'a> { sp, &format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)), ); + + // Try to recover extra trailing angle brackets + let mut recovered = false; + if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind { + if let Some(last_segment) = segments.last() { + recovered = self.check_trailing_angle_brackets( + last_segment, + &[&token::Comma, &token::CloseDelim(token::Brace)], + ); + if recovered { + // Handle a case like `Vec>,` where we can continue parsing fields + // after the comma + self.eat(&token::Comma); + // `check_trailing_angle_brackets` already emitted a nicer error + err.cancel(); + } + } + } + if self.token.is_ident() { // This is likely another field; emit the diagnostic and keep going err.span_suggestion( @@ -1271,6 +1290,14 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); err.emit(); + recovered = true; + } + + if recovered { + // Make sure an error was emitted (either by recovering an angle bracket, + // or by finding an identifier as the next token), since we're + // going to continue parsing + assert!(self.sess.span_diagnostic.has_errors()); } else { return Err(err); } diff --git a/src/librustc_parse/parser/path.rs b/src/librustc_parse/parser/path.rs index 5210614548da3..67e9b3af4a8cf 100644 --- a/src/librustc_parse/parser/path.rs +++ b/src/librustc_parse/parser/path.rs @@ -169,7 +169,7 @@ impl<'a> Parser<'a> { // `PathStyle::Expr` is only provided at the root invocation and never in // `parse_path_segment` to recurse and therefore can be checked to maintain // this invariant. - self.check_trailing_angle_brackets(&segment, token::ModSep); + self.check_trailing_angle_brackets(&segment, &[&token::ModSep]); } segments.push(segment); diff --git a/src/test/ui/parser/recover-field-extra-angle-brackets.rs b/src/test/ui/parser/recover-field-extra-angle-brackets.rs new file mode 100644 index 0000000000000..5e0e00bcb5e8d --- /dev/null +++ b/src/test/ui/parser/recover-field-extra-angle-brackets.rs @@ -0,0 +1,14 @@ +// Tests that we recover from extra trailing angle brackets +// in a struct field + +struct BadStruct { + first: Vec>, //~ ERROR unmatched angle bracket + second: bool +} + +fn bar(val: BadStruct) { + val.first; + val.second; +} + +fn main() {} diff --git a/src/test/ui/parser/recover-field-extra-angle-brackets.stderr b/src/test/ui/parser/recover-field-extra-angle-brackets.stderr new file mode 100644 index 0000000000000..318e55f6e99ac --- /dev/null +++ b/src/test/ui/parser/recover-field-extra-angle-brackets.stderr @@ -0,0 +1,8 @@ +error: unmatched angle bracket + --> $DIR/recover-field-extra-angle-brackets.rs:5:19 + | +LL | first: Vec>, + | ^ help: remove extra angle bracket + +error: aborting due to previous error + From 3fc5593ea80819f940f6edef3108d15ef2ad7956 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sat, 27 Jun 2020 18:33:15 +0200 Subject: [PATCH 28/92] Document the type keyword --- src/libstd/keyword_docs.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index d972cf6db18cf..3b493c4244de6 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1463,9 +1463,33 @@ mod true_keyword {} // /// Define an alias for an existing type. /// -/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// The syntax is `type Name = ExistingType;`. /// -/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +/// # Examples +/// +/// `type` does **not** create a new type: +/// +/// ```rust +/// type Meters = u32; +/// type Kilograms = u32; +/// +/// let m: Meters = 3; +/// let k: Kilograms = 3; +/// +/// assert_eq!(m, k); +/// ``` +/// +/// In traits, using `type` allows the usage of an associated type without +/// knowing about it when declaring the [`trait`]: +/// +/// ```rust +/// trait Iterator { +/// type Item; +/// fn next(&mut self) -> Option; +/// } +/// ``` +/// +/// [`trait`]: keyword.trait.html mod type_keyword {} #[doc(keyword = "unsafe")] From 8b43012453de32d4e429c923171131f938d3ead8 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Sat, 27 Jun 2020 18:24:46 +0100 Subject: [PATCH 29/92] Update src/librustc_mir/interpret/intrinsics.rs Co-authored-by: Oliver Scherer --- src/librustc_mir/interpret/intrinsics.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 52cb700c3d58f..983dc1dc81955 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -401,8 +401,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } sym::likely | sym::unlikely => { // These just return their argument - let a = self.read_immediate(args[0])?; - self.write_immediate(*a, dest)?; + self.copy_op(args[0], dest)?; } // FIXME(#73156): Handle source code coverage in const eval sym::count_code_region => (), From 517d361a1f78cf13d589d0f6b94f5ca005bef540 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 27 Jun 2020 13:54:56 -0400 Subject: [PATCH 30/92] Use an 'approximate' universal upper bound when reporting region errors Fixes #67765 When reporting errors during MIR region inference, we sometimes use `universal_upper_bound` to obtain a named universal region that we can display to the user. However, this is not always possible - in a case like `fn foo<'a, 'b>() { .. }`, the only upper bound for a region containing `'a` and `'b` is `'static`. When displaying diagnostics, it's usually better to display *some* named region (even if there are multiple involved) rather than fall back to a generic error involving `'static`. This commit adds a new `approx_universal_upper_bound` method, which uses the lowest-numbered universal region if the only alternative is to return `'static`. --- .../borrow_check/diagnostics/region_errors.rs | 4 ++- .../borrow_check/region_infer/mod.rs | 34 +++++++++++++++++++ .../borrow_check/region_infer/opaque_types.rs | 3 +- .../issue-67765-async-diagnostic.rs | 16 +++++++++ .../issue-67765-async-diagnostic.stderr | 12 +++++++ ...ure-doesnt-life-long-enough-issue-67634.rs | 2 +- ...doesnt-life-long-enough-issue-67634.stderr | 24 ++++++++----- src/test/ui/return-disjoint-regions.rs | 7 ++++ src/test/ui/return-disjoint-regions.stderr | 11 ++++++ 9 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/async-await/issue-67765-async-diagnostic.rs create mode 100644 src/test/ui/async-await/issue-67765-async-diagnostic.stderr create mode 100644 src/test/ui/return-disjoint-regions.rs create mode 100644 src/test/ui/return-disjoint-regions.stderr diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs index f1923b9e81c66..fa4846a20cbfb 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/region_errors.rs @@ -122,7 +122,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if self.regioncx.universal_regions().is_universal_region(r) { Some(r) } else { - let upper_bound = self.regioncx.universal_upper_bound(r); + // We just want something nameable, even if it's not + // actually an upper bound. + let upper_bound = self.regioncx.approx_universal_upper_bound(r); if self.regioncx.upper_bound_in_region_scc(r, upper_bound) { self.to_error_region_vid(upper_bound) diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/src/librustc_mir/borrow_check/region_infer/mod.rs index 3e459bd52f757..081125cb625c2 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/region_infer/mod.rs @@ -1114,6 +1114,40 @@ impl<'tcx> RegionInferenceContext<'tcx> { lub } + /// Like `universal_upper_bound`, but returns an approximation more suitable + /// for diagnostics. If `r` contains multiple disjoint universal regions + /// (e.g. 'a and 'b in `fn foo<'a, 'b> { ... }`, we pick the lower-numbered region. + /// This corresponds to picking named regions over unnamed regions + /// (e.g. picking early-bound regions over a closure late-bound region). + /// + /// This means that the returned value may not be a true upper bound, since + /// only 'static is known to outlive disjoint universal regions. + /// Therefore, this method should only be used in diagnostic code, + /// where displaying *some* named universal region is better than + /// falling back to 'static. + pub(in crate::borrow_check) fn approx_universal_upper_bound(&self, r: RegionVid) -> RegionVid { + debug!("approx_universal_upper_bound(r={:?}={})", r, self.region_value_str(r)); + + // Find the smallest universal region that contains all other + // universal regions within `region`. + let mut lub = self.universal_regions.fr_fn_body; + let r_scc = self.constraint_sccs.scc(r); + let static_r = self.universal_regions.fr_static; + for ur in self.scc_values.universal_regions_outlived_by(r_scc) { + let new_lub = self.universal_region_relations.postdom_upper_bound(lub, ur); + debug!("approx_universal_upper_bound: ur={:?} lub={:?} new_lub={:?}", ur, lub, new_lub); + if ur != static_r && lub != static_r && new_lub == static_r { + lub = std::cmp::min(ur, lub); + } else { + lub = new_lub; + } + } + + debug!("approx_universal_upper_bound: r={:?} lub={:?}", r, lub); + + lub + } + /// Tests if `test` is true when applied to `lower_bound` at /// `point`. fn eval_verify_bound( diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs index 7e352bfba77bc..325dca8c8ca99 100644 --- a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs +++ b/src/librustc_mir/borrow_check/region_infer/opaque_types.rs @@ -141,7 +141,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { { tcx.fold_regions(&ty, &mut false, |region, _| match *region { ty::ReVar(vid) => { - let upper_bound = self.universal_upper_bound(vid); + // Find something that we can name + let upper_bound = self.approx_universal_upper_bound(vid); self.definitions[upper_bound].external_name.unwrap_or(region) } _ => region, diff --git a/src/test/ui/async-await/issue-67765-async-diagnostic.rs b/src/test/ui/async-await/issue-67765-async-diagnostic.rs new file mode 100644 index 0000000000000..5093916e73a45 --- /dev/null +++ b/src/test/ui/async-await/issue-67765-async-diagnostic.rs @@ -0,0 +1,16 @@ +// edition:2018 +// +// Regression test for issue #67765 +// Tests that we point at the proper location when giving +// a lifetime error. +fn main() {} + +async fn func<'a>() -> Result<(), &'a str> { + let s = String::new(); + + let b = &s[..]; + + Err(b)?; //~ ERROR cannot return value referencing local variable `s` + + Ok(()) +} diff --git a/src/test/ui/async-await/issue-67765-async-diagnostic.stderr b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr new file mode 100644 index 0000000000000..78253042bee1c --- /dev/null +++ b/src/test/ui/async-await/issue-67765-async-diagnostic.stderr @@ -0,0 +1,12 @@ +error[E0515]: cannot return value referencing local variable `s` + --> $DIR/issue-67765-async-diagnostic.rs:13:11 + | +LL | let b = &s[..]; + | - `s` is borrowed here +LL | +LL | Err(b)?; + | ^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs index 19d7f0190479e..8deb365515840 100644 --- a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs +++ b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.rs @@ -1,3 +1,3 @@ fn main() { - [0].iter().flat_map(|a| [0].iter().map(|_| &a)); //~ ERROR `a` does not live long enough + [0].iter().flat_map(|a| [0].iter().map(|_| &a)); //~ ERROR closure may outlive } diff --git a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr index cb0b481e74876..34470119112fb 100644 --- a/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr +++ b/src/test/ui/lifetimes/unnamed-closure-doesnt-life-long-enough-issue-67634.stderr @@ -1,15 +1,21 @@ -error[E0597]: `a` does not live long enough - --> $DIR/unnamed-closure-doesnt-life-long-enough-issue-67634.rs:2:49 +error[E0373]: closure may outlive the current function, but it borrows `a`, which is owned by the current function + --> $DIR/unnamed-closure-doesnt-life-long-enough-issue-67634.rs:2:44 | LL | [0].iter().flat_map(|a| [0].iter().map(|_| &a)); - | - ^- ...but `a` will be dropped here, when the enclosing closure returns - | | | - | | `a` would have to be valid for `'_`... - | has type `&i32` + | ^^^ - `a` is borrowed here + | | + | may outlive borrowed value `a` | - = note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments - = note: to learn more, visit +note: closure is returned here + --> $DIR/unnamed-closure-doesnt-life-long-enough-issue-67634.rs:2:29 + | +LL | [0].iter().flat_map(|a| [0].iter().map(|_| &a)); + | ^^^^^^^^^^^^^^^^^^^^^^ +help: to force the closure to take ownership of `a` (and any other referenced variables), use the `move` keyword + | +LL | [0].iter().flat_map(|a| [0].iter().map(move |_| &a)); + | ^^^^^^^^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0373`. diff --git a/src/test/ui/return-disjoint-regions.rs b/src/test/ui/return-disjoint-regions.rs new file mode 100644 index 0000000000000..d0feb3b65e12a --- /dev/null +++ b/src/test/ui/return-disjoint-regions.rs @@ -0,0 +1,7 @@ +// See https://github.com/rust-lang/rust/pull/67911#issuecomment-576023915 +fn f<'a, 'b>(x: i32) -> (&'a i32, &'b i32) { + let y = &x; + (y, y) //~ ERROR cannot return +} + +fn main() {} diff --git a/src/test/ui/return-disjoint-regions.stderr b/src/test/ui/return-disjoint-regions.stderr new file mode 100644 index 0000000000000..ed159298804ae --- /dev/null +++ b/src/test/ui/return-disjoint-regions.stderr @@ -0,0 +1,11 @@ +error[E0515]: cannot return value referencing function parameter `x` + --> $DIR/return-disjoint-regions.rs:4:5 + | +LL | let y = &x; + | -- `x` is borrowed here +LL | (y, y) + | ^^^^^^ returns a value referencing data owned by the current function + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0515`. From 8e899b1cbe6209842e112f0b7ec450a3cdfdb36d Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 27 Jun 2020 15:51:51 -0400 Subject: [PATCH 31/92] Don't implement Fn* for unsafe #[target_feature] functions --- .../traits/error_reporting/mod.rs | 8 +++----- .../ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 39530853318e3..76e01a40a2362 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -292,11 +292,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.lang_items().fn_once_trait(), ] .contains(&Some(trait_ref.def_id())); - let is_safe_target_feature_fn = + let is_target_feature_fn = if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind { - trait_ref.skip_binder().self_ty().fn_sig(self.tcx).unsafety() - == hir::Unsafety::Normal - && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() + !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() } else { false }; @@ -441,7 +439,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); } - if is_fn_trait && is_safe_target_feature_fn { + if is_fn_trait && is_target_feature_fn { err.note(&format!( "`{}` has `#[target_feature]` and is unsafe to call", trait_ref.skip_binder().self_ty(), diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index 3ae85af76d306..ba3d2eac1a6b0 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -48,6 +48,7 @@ LL | call(foo_unsafe); | = help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + = note: `unsafe fn() {foo_unsafe}` has `#[target_feature]` and is unsafe to call error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:30:14 @@ -60,6 +61,7 @@ LL | call_mut(foo_unsafe); | = help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + = note: `unsafe fn() {foo_unsafe}` has `#[target_feature]` and is unsafe to call error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:32:15 @@ -72,6 +74,7 @@ LL | call_once(foo_unsafe); | = help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } + = note: `unsafe fn() {foo_unsafe}` has `#[target_feature]` and is unsafe to call error: aborting due to 6 previous errors From 7055c23d2cb3baabbae6af7ab196e43035260856 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 24 Jun 2020 17:45:08 +0300 Subject: [PATCH 32/92] ast_pretty: Pass some token streams and trees by reference --- src/librustc_ast_pretty/pprust.rs | 38 +++++++++++----------- src/librustc_builtin_macros/log_syntax.rs | 2 +- src/librustc_builtin_macros/source_util.rs | 2 +- src/librustc_expand/mbe/macro_rules.rs | 4 +-- src/librustc_expand/proc_macro_server.rs | 2 +- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 86faa1f086ce2..501cd3748282b 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -9,7 +9,7 @@ use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::util::parser::{self, AssocOp, Fixity}; use rustc_ast::util::{classify, comments}; use rustc_span::edition::Edition; @@ -293,7 +293,7 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String { token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(), token::NtLifetime(e) => e.to_string(), token::NtLiteral(ref e) => expr_to_string(e), - token::NtTT(ref tree) => tt_to_string(tree.clone()), + token::NtTT(ref tree) => tt_to_string(tree), token::NtVis(ref e) => vis_to_string(e), } } @@ -314,11 +314,11 @@ pub fn expr_to_string(e: &ast::Expr) -> String { to_string(|s| s.print_expr(e)) } -pub fn tt_to_string(tt: tokenstream::TokenTree) -> String { +pub fn tt_to_string(tt: &TokenTree) -> String { to_string(|s| s.print_tt(tt, false)) } -pub fn tts_to_string(tokens: TokenStream) -> String { +pub fn tts_to_string(tokens: &TokenStream) -> String { to_string(|s| s.print_tts(tokens, false)) } @@ -585,7 +585,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere false, None, delim.to_token(), - tokens.clone(), + tokens, true, span, ), @@ -594,7 +594,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere if let MacArgs::Eq(_, tokens) = &item.args { self.space(); self.word_space("="); - self.print_tts(tokens.clone(), true); + self.print_tts(tokens, true); } } } @@ -635,9 +635,9 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere /// appropriate macro, transcribe back into the grammar we just parsed from, /// and then pretty-print the resulting AST nodes (so, e.g., we print /// expression arguments as expressions). It can be done! I think. - fn print_tt(&mut self, tt: tokenstream::TokenTree, convert_dollar_crate: bool) { + fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) { match tt { - TokenTree::Token(ref token) => { + TokenTree::Token(token) => { self.word(token_to_string_ext(&token, convert_dollar_crate)); if let token::DocComment(..) = token.kind { self.hardbreak() @@ -648,7 +648,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere None, false, None, - delim, + *delim, tts, convert_dollar_crate, dspan.entire(), @@ -657,14 +657,14 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere } } - fn print_tts(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) { - let mut iter = tts.into_trees().peekable(); + fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) { + let mut iter = tts.trees().peekable(); while let Some(tt) = iter.next() { - let show_space = - if let Some(next) = iter.peek() { tt_prepend_space(next, &tt) } else { false }; - self.print_tt(tt, convert_dollar_crate); - if show_space { - self.space(); + self.print_tt(&tt, convert_dollar_crate); + if let Some(next) = iter.peek() { + if tt_prepend_space(next, &tt) { + self.space(); + } } } } @@ -675,7 +675,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere has_bang: bool, ident: Option, delim: DelimToken, - tts: TokenStream, + tts: &TokenStream, convert_dollar_crate: bool, span: Span, ) { @@ -1253,7 +1253,7 @@ impl<'a> State<'a> { has_bang, Some(item.ident), macro_def.body.delim(), - macro_def.body.inner_tokens(), + ¯o_def.body.inner_tokens(), true, item.span, ); @@ -1577,7 +1577,7 @@ impl<'a> State<'a> { true, None, m.args.delim(), - m.args.inner_tokens(), + &m.args.inner_tokens(), true, m.span(), ); diff --git a/src/librustc_builtin_macros/log_syntax.rs b/src/librustc_builtin_macros/log_syntax.rs index ae3a889428ae4..ede34a7612589 100644 --- a/src/librustc_builtin_macros/log_syntax.rs +++ b/src/librustc_builtin_macros/log_syntax.rs @@ -7,7 +7,7 @@ pub fn expand_log_syntax<'cx>( sp: rustc_span::Span, tts: TokenStream, ) -> Box { - println!("{}", pprust::tts_to_string(tts)); + println!("{}", pprust::tts_to_string(&tts)); // any so that `log_syntax` can be invoked as an expression and item. base::DummyResult::any_valid(sp) diff --git a/src/librustc_builtin_macros/source_util.rs b/src/librustc_builtin_macros/source_util.rs index 1b164eae5a345..e46cf67e64d66 100644 --- a/src/librustc_builtin_macros/source_util.rs +++ b/src/librustc_builtin_macros/source_util.rs @@ -71,7 +71,7 @@ pub fn expand_stringify( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let s = pprust::tts_to_string(tts); + let s = pprust::tts_to_string(&tts); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))) } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 8cdb5b09c9e8b..28a3970918ee6 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -224,7 +224,7 @@ fn generic_extension<'cx>( let sess = cx.parse_sess; if cx.trace_macros() { - let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(arg.clone())); + let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(&arg)); trace_macros_note(&mut cx.expansions, sp, msg); } @@ -300,7 +300,7 @@ fn generic_extension<'cx>( } if cx.trace_macros() { - let msg = format!("to `{}`", pprust::tts_to_string(tts.clone())); + let msg = format!("to `{}`", pprust::tts_to_string(&tts)); trace_macros_note(&mut cx.expansions, sp, msg); } diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index c88b5a37f718a..e5e530227e43a 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -413,7 +413,7 @@ impl server::TokenStream for Rustc<'_> { ) } fn to_string(&mut self, stream: &Self::TokenStream) -> String { - pprust::tts_to_string(stream.clone()) + pprust::tts_to_string(stream) } fn from_token_tree( &mut self, From 14d03702735ccca48f5b954db6c01e9cedb14f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 28 Jun 2020 00:00:00 +0000 Subject: [PATCH 33/92] Remove defunct `-Z print-region-graph` --- src/librustc_interface/tests.rs | 1 - src/librustc_session/options.rs | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index d861b444c8816..e35dbbc0c2f24 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -500,7 +500,6 @@ fn test_debugging_options_tracking_hash() { untracked!(print_link_args, true); untracked!(print_llvm_passes, true); untracked!(print_mono_items, Some(String::from("abc"))); - untracked!(print_region_graph, true); untracked!(print_type_sizes, true); untracked!(query_dep_graph, true); untracked!(query_stats, true); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 9337f241d7022..ed5fd6dc7028b 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -958,9 +958,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print the LLVM optimization passes being run (default: no)"), print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], "print the result of the monomorphization collection pass"), - print_region_graph: bool = (false, parse_bool, [UNTRACKED], - "prints region inference graph. \ - Use with RUST_REGION_GRAPH=help for more info (default: no)"), print_type_sizes: bool = (false, parse_bool, [UNTRACKED], "print layout information for each type encountered (default: no)"), profile: bool = (false, parse_bool, [TRACKED], From 7231e575461d1246c247b2ac3e97c1adcab49737 Mon Sep 17 00:00:00 2001 From: James Box Date: Sat, 27 Jun 2020 22:55:42 -0500 Subject: [PATCH 34/92] Fix wording for anonymous parameter name help --- src/librustc_parse/parser/diagnostics.rs | 2 +- src/test/ui/anon-params/anon-params-denied-2018.stderr | 8 ++++---- src/test/ui/parser/inverted-parameters.rs | 2 +- src/test/ui/parser/inverted-parameters.stderr | 2 +- src/test/ui/parser/omitted-arg-in-item-fn.stderr | 2 +- src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr | 2 +- src/test/ui/span/issue-34264.stderr | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index fc9ffc3092447..e27bbc532cfc4 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1415,7 +1415,7 @@ impl<'a> Parser<'a> { if self.token != token::Lt { err.span_suggestion( pat.span, - "if this was a parameter name, give it a type", + "if this is a parameter name, give it a type", format!("{}: TypeName", ident), Applicability::HasPlaceholders, ); diff --git a/src/test/ui/anon-params/anon-params-denied-2018.stderr b/src/test/ui/anon-params/anon-params-denied-2018.stderr index e7a806a846820..840294db0830a 100644 --- a/src/test/ui/anon-params/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params/anon-params-denied-2018.stderr @@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn foo(self: i32); | ^^^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn foo(i32: TypeName); | ^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn bar_with_default_impl(self: String, String) {} | ^^^^^^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn bar_with_default_impl(String: TypeName, String) {} | ^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | fn bar_with_default_impl(String, String) {} | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn bar_with_default_impl(String, String: TypeName) {} | ^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | fn baz(a:usize, b, c: usize) -> usize { | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn baz(a:usize, b: TypeName, c: usize) -> usize { | ^^^^^^^^^^^ diff --git a/src/test/ui/parser/inverted-parameters.rs b/src/test/ui/parser/inverted-parameters.rs index 6f19ee9c7dc0d..5c4272504e061 100644 --- a/src/test/ui/parser/inverted-parameters.rs +++ b/src/test/ui/parser/inverted-parameters.rs @@ -20,7 +20,7 @@ fn pattern((i32, i32) (a, b)) {} fn fizz(i32) {} //~^ ERROR expected one of `:`, `@` -//~| HELP if this was a parameter name, give it a type +//~| HELP if this is a parameter name, give it a type //~| HELP if this is a `self` type, give it a parameter name //~| HELP if this is a type, explicitly ignore the parameter name diff --git a/src/test/ui/parser/inverted-parameters.stderr b/src/test/ui/parser/inverted-parameters.stderr index 043ff65f74e1a..ae180af93e373 100644 --- a/src/test/ui/parser/inverted-parameters.stderr +++ b/src/test/ui/parser/inverted-parameters.stderr @@ -39,7 +39,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn fizz(self: i32) {} | ^^^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn fizz(i32: TypeName) {} | ^^^^^^^^^^^^^ diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.stderr b/src/test/ui/parser/omitted-arg-in-item-fn.stderr index 9f138bf84ce19..bc3329dcbc23d 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.stderr +++ b/src/test/ui/parser/omitted-arg-in-item-fn.stderr @@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn foo(self: x) { | ^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn foo(x: TypeName) { | ^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr index 1e51567a9b1c4..5516d4a4c1c1c 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -9,7 +9,7 @@ help: if this is a `self` type, give it a parameter name | LL | trait Trait2015 { fn foo(#[allow(C)] self: i32); } | ^^^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | trait Trait2015 { fn foo(#[allow(C)] i32: TypeName); } | ^^^^^^^^^^^^^ diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 116f5ddd5b4b2..40c3219bf27b0 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -21,7 +21,7 @@ LL | fn foo(Option, String) {} | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn foo(Option, String: TypeName) {} | ^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ help: if this is a `self` type, give it a parameter name | LL | fn bar(self: x, y: usize) {} | ^^^^^^^ -help: if this was a parameter name, give it a type +help: if this is a parameter name, give it a type | LL | fn bar(x: TypeName, y: usize) {} | ^^^^^^^^^^^ From 4595fa8a1baf95b0a19aae3d84e945344d8f8a44 Mon Sep 17 00:00:00 2001 From: pierwill Date: Sun, 28 Jun 2020 00:06:48 -0700 Subject: [PATCH 35/92] Fix comma in debug_assert! docs --- src/libcore/macros/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index 3cfdde60135b7..5620d26af40a2 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -151,7 +151,7 @@ macro_rules! assert_ne { /// An unchecked assertion allows a program in an inconsistent state to keep /// running, which might have unexpected consequences but does not introduce /// unsafety as long as this only happens in safe code. The performance cost -/// of assertions, is however, not measurable in general. Replacing [`assert!`] +/// of assertions, however, is not measurable in general. Replacing [`assert!`] /// with `debug_assert!` is thus only encouraged after thorough profiling, and /// more importantly, only in safe code! /// From e611a3fb8423f178e856813fc1a1f2397980bd8a Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 28 Jun 2020 17:20:27 +0200 Subject: [PATCH 36/92] Apply suggestions from code review --- src/libstd/keyword_docs.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 3b493c4244de6..089056d68f803 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1479,17 +1479,28 @@ mod true_keyword {} /// assert_eq!(m, k); /// ``` /// -/// In traits, using `type` allows the usage of an associated type without -/// knowing about it when declaring the [`trait`]: +/// In traits, `type` is used to declare an [associated type]: /// /// ```rust /// trait Iterator { +/// // associated type declaration /// type Item; /// fn next(&mut self) -> Option; /// } +/// +/// struct Once(Option); +/// +/// impl Iterator for Once { +/// // associated type definition +/// type Item = T; +/// fn next(&mut self) -> Option { +/// self.0.take() +/// } +/// } /// ``` /// /// [`trait`]: keyword.trait.html +/// [associated type]: ../reference/items/associated-items.html#associated-types mod type_keyword {} #[doc(keyword = "unsafe")] From e8f5785bfc3123b67e79e509c76259062e214b97 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Sun, 28 Jun 2020 23:28:43 +0800 Subject: [PATCH 37/92] Split and expand nonstandard-style lints unicode unit test. --- .../lint/lint-nonstandard-style-unicode-1.rs | 50 +++++++++++++++++++ .../lint-nonstandard-style-unicode-1.stderr | 50 +++++++++++++++++++ .../lint/lint-nonstandard-style-unicode-2.rs | 30 +++++++++++ .../lint-nonstandard-style-unicode-2.stderr | 20 ++++++++ .../lint/lint-nonstandard-style-unicode-3.rs | 25 ++++++++++ .../lint-nonstandard-style-unicode-3.stderr | 14 ++++++ .../ui/lint/lint-nonstandard-style-unicode.rs | 16 ------ 7 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-1.rs create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-1.stderr create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-2.rs create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-2.stderr create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-3.rs create mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode-3.stderr delete mode 100644 src/test/ui/lint/lint-nonstandard-style-unicode.rs diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-1.rs b/src/test/ui/lint/lint-nonstandard-style-unicode-1.rs new file mode 100644 index 0000000000000..4f90bd98c63e5 --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-1.rs @@ -0,0 +1,50 @@ +#![allow(dead_code)] + +#![forbid(non_camel_case_types)] +#![feature(non_ascii_idents)] + +// Some scripts (e.g., hiragana) don't have a concept of +// upper/lowercase + +// 1. non_camel_case_types + +// Can start with non-lowercase letter +struct Θχ; +struct ヒa; + +struct χa; +//~^ ERROR type `χa` should have an upper camel case name + +// If there's already leading or trailing underscores, they get trimmed before checking. +// This is fine: +struct _ヒb; + +// This is not: +struct __χa; +//~^ ERROR type `__χa` should have an upper camel case name + +// Besides this, we cannot have two continous underscores in the middle. + +struct 对__否; +//~^ ERROR type `对__否` should have an upper camel case name + +struct ヒ__χ; +//~^ ERROR type `ヒ__χ` should have an upper camel case name + +// also cannot have lowercase letter next to a underscore. +// so this triggers the lint: + +struct Hello_你好; +//~^ ERROR type `Hello_你好` should have an upper camel case name + +struct Hello_World; +//~^ ERROR type `Hello_World` should have an upper camel case name + +struct 你_ӟ; +//~^ ERROR type `你_ӟ` should have an upper camel case name + +// and this is ok: + +struct 你_好; + +fn main() {} diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-1.stderr b/src/test/ui/lint/lint-nonstandard-style-unicode-1.stderr new file mode 100644 index 0000000000000..371002656591c --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-1.stderr @@ -0,0 +1,50 @@ +error: type `χa` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:15:8 + | +LL | struct χa; + | ^^ help: convert the identifier to upper camel case: `Χa` + | +note: the lint level is defined here + --> $DIR/lint-nonstandard-style-unicode-1.rs:3:11 + | +LL | #![forbid(non_camel_case_types)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: type `__χa` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:23:8 + | +LL | struct __χa; + | ^^^^ help: convert the identifier to upper camel case: `Χa` + +error: type `对__否` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:28:8 + | +LL | struct 对__否; + | ^^^^^^ help: convert the identifier to upper camel case: `对_否` + +error: type `ヒ__χ` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:31:8 + | +LL | struct ヒ__χ; + | ^^^^^ help: convert the identifier to upper camel case: `ヒΧ` + +error: type `Hello_你好` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:37:8 + | +LL | struct Hello_你好; + | ^^^^^^^^^^ help: convert the identifier to upper camel case: `Hello你好` + +error: type `Hello_World` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:40:8 + | +LL | struct Hello_World; + | ^^^^^^^^^^^ help: convert the identifier to upper camel case: `HelloWorld` + +error: type `你_ӟ` should have an upper camel case name + --> $DIR/lint-nonstandard-style-unicode-1.rs:43:8 + | +LL | struct 你_ӟ; + | ^^^^ help: convert the identifier to upper camel case: `你Ӟ` + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-2.rs b/src/test/ui/lint/lint-nonstandard-style-unicode-2.rs new file mode 100644 index 0000000000000..813e0ea5c5708 --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-2.rs @@ -0,0 +1,30 @@ +#![allow(dead_code)] + +#![forbid(non_snake_case)] +#![feature(non_ascii_idents)] + +// Some scripts (e.g., hiragana) don't have a concept of +// upper/lowercase + +// 2. non_snake_case + +// Can only use non-uppercase letters. +// So this works: + +fn 编程() {} + +// but this doesn't: + +fn Ц() {} +//~^ ERROR function `Ц` should have a snake case name + +// besides this, you cannot use continous underscores in the middle + +fn 分__隔() {} +//~^ ERROR function `分__隔` should have a snake case name + +// but you can use them both at the beginning and at the end. + +fn _______不_连_续_的_存_在_______() {} + +fn main() {} diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-2.stderr b/src/test/ui/lint/lint-nonstandard-style-unicode-2.stderr new file mode 100644 index 0000000000000..0b309e315a411 --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-2.stderr @@ -0,0 +1,20 @@ +error: function `Ц` should have a snake case name + --> $DIR/lint-nonstandard-style-unicode-2.rs:18:4 + | +LL | fn Ц() {} + | ^ help: convert the identifier to snake case: `ц` + | +note: the lint level is defined here + --> $DIR/lint-nonstandard-style-unicode-2.rs:3:11 + | +LL | #![forbid(non_snake_case)] + | ^^^^^^^^^^^^^^ + +error: function `分__隔` should have a snake case name + --> $DIR/lint-nonstandard-style-unicode-2.rs:23:4 + | +LL | fn 分__隔() {} + | ^^^^^^ help: convert the identifier to snake case: `分_隔` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-3.rs b/src/test/ui/lint/lint-nonstandard-style-unicode-3.rs new file mode 100644 index 0000000000000..b17c2de39a0c0 --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-3.rs @@ -0,0 +1,25 @@ +#![allow(dead_code)] + +#![forbid(non_upper_case_globals)] +#![feature(non_ascii_idents)] + +// Some scripts (e.g., hiragana) don't have a concept of +// upper/lowercase + +// 3. non_upper_case_globals + +// Can only use non-lowercase letters. +// So this works: + +static ラ: usize = 0; + +// but this doesn't: + +static τεχ: f32 = 3.14159265; +//~^ ERROR static variable `τεχ` should have an upper case name + +// This has no limit at all on underscore usages. + +static __密__封__线__内__禁__止__答__题__: bool = true; + +fn main() {} diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode-3.stderr b/src/test/ui/lint/lint-nonstandard-style-unicode-3.stderr new file mode 100644 index 0000000000000..44bd5ad55ff5c --- /dev/null +++ b/src/test/ui/lint/lint-nonstandard-style-unicode-3.stderr @@ -0,0 +1,14 @@ +error: static variable `τεχ` should have an upper case name + --> $DIR/lint-nonstandard-style-unicode-3.rs:18:8 + | +LL | static τεχ: f32 = 3.14159265; + | ^^^ help: convert the identifier to upper case: `ΤΕΧ` + | +note: the lint level is defined here + --> $DIR/lint-nonstandard-style-unicode-3.rs:3:11 + | +LL | #![forbid(non_upper_case_globals)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-nonstandard-style-unicode.rs b/src/test/ui/lint/lint-nonstandard-style-unicode.rs deleted file mode 100644 index 9f16cb20fb32c..0000000000000 --- a/src/test/ui/lint/lint-nonstandard-style-unicode.rs +++ /dev/null @@ -1,16 +0,0 @@ -// check-pass - -#![allow(dead_code)] - -#![forbid(non_camel_case_types)] -#![forbid(non_upper_case_globals)] -#![feature(non_ascii_idents)] - -// Some scripts (e.g., hiragana) don't have a concept of -// upper/lowercase - -struct ヒ; - -static ラ: usize = 0; - -pub fn main() {} From dfd454bd3843c4f4dee2e943297bf3d208252dc6 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 28 Jun 2020 20:20:32 +0200 Subject: [PATCH 38/92] Apply suggestions, reformulating some paragraphs and improving some examples --- src/libstd/keyword_docs.rs | 74 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 746165beab8f5..d84ed1c93dee4 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1030,22 +1030,39 @@ mod self_upper_keyword {} // /// A place that is valid for the duration of a program. /// -/// A `static` item is similar to a [`const`] item in that it lives for the -/// entire duration of the program and need to have its type explicited, with a -/// `static` lifetime, outliving any other lifetime. Added to that, `static` -/// items represent a precise memory location. +/// A static item is a value which is valid for the entire duration of your +/// program (a `'static` lifetime). +/// +/// On the surface, `static` items seem very similar to [`const`]s: both contain +/// a value, both require type annotations and both can only be initialized with +/// constant functions and values. However, `static`s are notably different in +/// that they represent a location in memory. That means that you can have +/// references to `static` items and potentially even modify them, making them +/// essentially global variables. /// /// Static items do not call [`drop`] at the end of the program. /// /// There are two types of `static` items: those declared in association with /// the [`mut`] keyword and those without. /// +/// Items that are both static and owned cannot be moved: +/// +/// ```rust,compile_fail,E0507 +/// static VEC: Vec = vec![]; +/// +/// fn move_vec(v: Vec) -> Vec { +/// v +/// } +/// +/// move_vec(VEC); +/// ``` +/// /// # Simple `static`s /// -/// Non-[`mut`] `static` items that contain a type that is not interior mutable -/// may be placed in read-only memory. All access to a `static` item are -/// considered safe but some restrictions apply. See the [Reference] for more -/// information. +/// Accessing non-[`mut`] `static` items is considered safe, but some +/// restrictions apply. Most notably, the type of a `static` value needs to +/// implement the [`Sync`] trait, ruling out interior mutability containers +/// like [`RefCell`]. See the [Reference] for more information. /// /// ```rust /// static FOO: [i32; 5] = [1, 2, 3, 4, 5]; @@ -1054,43 +1071,22 @@ mod self_upper_keyword {} /// let r2 = &FOO as *const _; /// // With a strictly read-only static, references will have the same adress /// assert_eq!(r1, r2); +/// // A static item is used just like a variable +/// println!("{:?}", FOO); /// ``` /// /// # Mutable `static`s /// /// If a `static` item is declared with the [`mut`] keyword, then it is allowed -/// to be modified by the program. To make concurrency bugs hard to run into, -/// all access to a `static mut` require an [`unsafe`] block. Care should be -/// taken to ensure access (both read and write) are thread-safe. +/// to be modified by the program. However, accessing mutable `static`s can +/// cause undefined behavior in a number of ways, for example due to data races +/// in a multithreaded context. As such, all accesses to mutable `static`s +/// require an [`unsafe`] block. /// -/// Despite their unsafety, mutable `static`s are very useful: they can be used -/// to represent global state shared by the whole program or be used in +/// Despite their unsafety, mutable `static`s are necessary in many contexts: +/// they can be used to represent global state shared by the whole program or in /// [`extern`] blocks to bind to variables from C libraries. /// -/// As global state: -/// -/// ```rust -/// # #![allow(unused_variables)] -/// # fn main() {} -/// # fn atomic_add(_: &mut u32, _: u32) -> u32 { 2 } -/// static mut LEVELS: u32 = 0; -/// -/// // This violates the idea of no shared state, and this doesn't internally -/// // protect against races, so this function is `unsafe` -/// unsafe fn bump_levels_unsafe1() -> u32 { -/// let ret = LEVELS; -/// LEVELS += 1; -/// return ret; -/// } -/// -/// // Assuming that we have an atomic_add function which returns the old value, -/// // this function is "safe" but the meaning of the return value may not be -/// // what callers expect, so it's still marked as `unsafe` -/// unsafe fn bump_levels_unsafe2() -> u32 { -/// return atomic_add(&mut LEVELS, 1); -/// } -/// ``` -/// /// In an [`extern`] block: /// /// ```rust,no_run @@ -1108,7 +1104,9 @@ mod self_upper_keyword {} /// [`mut`]: keyword.mut.html /// [`unsafe`]: keyword.unsafe.html /// [`drop`]: mem/fn.drop.html -/// [Reference]: ../reference/items/static-items.html#static-items +/// [`Sync`]: marker/trait.Sync.html +/// [`RefCell`]: cell/struct.RefCell.html +/// [Reference]: ../reference/items/static-items.html mod static_keyword {} #[doc(keyword = "struct")] From 4224313e2bc3fc08e5eee0519d7b5813c3cad580 Mon Sep 17 00:00:00 2001 From: Alexis Bourget Date: Sun, 28 Jun 2020 20:48:53 +0200 Subject: [PATCH 39/92] Fix small nits --- src/libstd/keyword_docs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index d84ed1c93dee4..3bae720270eba 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1028,8 +1028,6 @@ mod self_upper_keyword {} #[doc(keyword = "static")] // -/// A place that is valid for the duration of a program. -/// /// A static item is a value which is valid for the entire duration of your /// program (a `'static` lifetime). /// @@ -1045,7 +1043,7 @@ mod self_upper_keyword {} /// There are two types of `static` items: those declared in association with /// the [`mut`] keyword and those without. /// -/// Items that are both static and owned cannot be moved: +/// Static items cannot be moved: /// /// ```rust,compile_fail,E0507 /// static VEC: Vec = vec![]; @@ -1054,6 +1052,7 @@ mod self_upper_keyword {} /// v /// } /// +/// // This line causes an error /// move_vec(VEC); /// ``` /// @@ -1071,7 +1070,7 @@ mod self_upper_keyword {} /// let r2 = &FOO as *const _; /// // With a strictly read-only static, references will have the same adress /// assert_eq!(r1, r2); -/// // A static item is used just like a variable +/// // A static item can be used just like a variable in many cases /// println!("{:?}", FOO); /// ``` /// From 49c1018d139746f926f1af03d1d4282e0fed7115 Mon Sep 17 00:00:00 2001 From: pierwill Date: Sun, 28 Jun 2020 13:19:59 -0700 Subject: [PATCH 40/92] Fix markdown rendering in librustc_lexer docs Use back-ticks instead of quotation marks in docs for the block comment variant of TokenKind. --- src/librustc_lexer/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index 77b3d26463dfe..2f4b1bbd3ba0f 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -51,8 +51,9 @@ pub enum TokenKind { // Multi-char tokens: /// "// comment" LineComment, - /// "/* block comment */" - /// Block comments can be recursive, so the sequence like "/* /* */" + /// `/* block comment */` + /// + /// Block comments can be recursive, so the sequence like `/* /* */` /// will not be considered terminated and will result in a parsing error. BlockComment { terminated: bool }, /// Any whitespace characters sequence. From 40c74a7eb709f3f072d35b4264c614a9a8f6c2f9 Mon Sep 17 00:00:00 2001 From: pierwill Date: Sun, 28 Jun 2020 12:32:58 -0700 Subject: [PATCH 41/92] Edit cursor.prev() method docs in lexer Fix missing punctuation --- src/librustc_lexer/src/cursor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_lexer/src/cursor.rs b/src/librustc_lexer/src/cursor.rs index ed0911379c4b3..c0045d3f79be1 100644 --- a/src/librustc_lexer/src/cursor.rs +++ b/src/librustc_lexer/src/cursor.rs @@ -23,8 +23,8 @@ impl<'a> Cursor<'a> { } } - /// For debug assertions only - /// Returns the last eaten symbol (or '\0' in release builds). + /// Returns the last eaten symbol (or `'\0'` in release builds). + /// (For debug assertions only.) pub(crate) fn prev(&self) -> char { #[cfg(debug_assertions)] { From 49662726afdd6f4538bada73db771b939d92bd22 Mon Sep 17 00:00:00 2001 From: pierwill Date: Sun, 28 Jun 2020 15:38:39 -0700 Subject: [PATCH 42/92] Add newline to rustc MultiSpan docs Also adds back-ticks when referring to the contents of this collection. --- src/librustc_span/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index dcd2e83b74713..d630e03537c71 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -309,7 +309,9 @@ impl Ord for Span { } } -/// A collection of spans. Spans have two orthogonal attributes: +/// A collection of `Span`s. +/// +/// Spans have two orthogonal attributes: /// /// - They can be *primary spans*. In this case they are the locus of /// the error, and would be rendered with `^^^`. From 3dfbf0bc738d1ba4ee0f084ce3f32074fceee3bb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 15 Jun 2020 07:54:20 -0700 Subject: [PATCH 43/92] rustbuild: Move compiler-builtins build logic to manifest This commit moves the compiler-builtins-specific build logic from `src/bootstrap/bin/rustc.rs` into the workspace `Cargo.toml`'s `[profile]` configuration. Now that rust-lang/cargo#7253 is fixed we can ensure that Cargo knows about debug assertions settings, and it can also be configured to specifically disable debug assertions unconditionally for compiler-builtins. This should improve rebuild logic when debug-assertions settings change and also improve build-std integration where Cargo externally now has an avenue to learn how to build compiler-builtins as well. --- Cargo.toml | 16 ++++++++-------- src/bootstrap/bin/rustc.rs | 24 ------------------------ src/bootstrap/builder.rs | 16 ++++++++-------- 3 files changed, 16 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f10d539d8296b..be15e50e2bcca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,16 +33,16 @@ exclude = [ "obj", ] -# These options are controlled from our rustc wrapper script, so turn them off -# here and have them controlled elsewhere. -[profile.dev] -debug = false -debug-assertions = false -[profile.test] -debug = false +[profile.release.package.compiler_builtins] +# The compiler-builtins crate cannot reference libcore, and it's own CI will +# verify that this is the case. This requires, however, that the crate is built +# without overflow checks and debug assertions. Forcefully disable debug +# assertions and overflow checks here which should ensure that even if these +# assertions are enabled for libstd we won't enable then for compiler_builtins +# which should ensure we still link everything correctly. debug-assertions = false +overflow-checks = false -[profile.release.package.compiler_builtins] # For compiler-builtins we always use a high number of codegen units. # The goal here is to place every single intrinsic into its own object # file to avoid symbol clashes with the system libgcc if possible. Note diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a8c00c8c3ca88..3072a4a1ae7c0 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -101,30 +101,6 @@ fn main() { { cmd.arg("-C").arg("panic=abort"); } - - // Set various options from config.toml to configure how we're building - // code. - let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") { - Ok(s) => { - if s == "true" { - "y" - } else { - "n" - } - } - Err(..) => "n", - }; - - // The compiler builtins are pretty sensitive to symbols referenced in - // libcore and such, so we never compile them with debug assertions. - // - // FIXME(rust-lang/cargo#7253) we should be doing this in `builder.rs` - // with env vars instead of doing it here in this script. - if crate_name == Some("compiler_builtins") { - cmd.arg("-C").arg("debug-assertions=no"); - } else { - cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); - } } else { // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars // here, but rather Cargo should know what flags to pass rustc itself. diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0735ba8869add..c5e2a4a38cff5 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -950,14 +950,6 @@ impl<'a> Builder<'a> { .env("RUSTC", self.out.join("bootstrap/debug/rustc")) .env("RUSTC_REAL", self.rustc(compiler)) .env("RUSTC_STAGE", stage.to_string()) - .env( - "RUSTC_DEBUG_ASSERTIONS", - if mode == Mode::Std { - self.config.rust_debug_assertions_std.to_string() - } else { - self.config.rust_debug_assertions.to_string() - }, - ) .env("RUSTC_SYSROOT", &sysroot) .env("RUSTC_LIBDIR", &libdir) .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) @@ -1041,6 +1033,14 @@ impl<'a> Builder<'a> { } }; cargo.env(profile_var("DEBUG"), debuginfo_level.to_string()); + cargo.env( + profile_var("DEBUG_ASSERTIONS"), + if mode == Mode::Std { + self.config.rust_debug_assertions_std.to_string() + } else { + self.config.rust_debug_assertions.to_string() + }, + ); if !mode.is_tool() { cargo.env("RUSTC_FORCE_UNSTABLE", "1"); From c8f2dd0d3b41419113f42f55533849526b7c150c Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 29 Jun 2020 17:20:01 +0200 Subject: [PATCH 44/92] Revert "ci: allow gating gha on everything but macOS" This reverts commit 8bc3122311dd70eabb0020e67e850b2b7904d972. --- .github/workflows/ci.yml | 158 +++++++---------------------------- src/ci/github-actions/ci.yml | 81 ++++++++---------- 2 files changed, 65 insertions(+), 174 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b9f87c079e3a..5f9311635f6bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -369,6 +369,35 @@ jobs: env: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json os: ubuntu-latest-xl + - name: dist-x86_64-apple + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + os: macos-latest + - name: dist-x86_64-apple-alt + env: + SCRIPT: "./x.py dist" + RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest + - name: x86_64-apple + env: + SCRIPT: "./x.py test" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + os: macos-latest - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" @@ -551,135 +580,6 @@ jobs: AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" - auto-fallible: - name: auto-fallible - env: - CI_JOB_NAME: "${{ matrix.name }}" - SCCACHE_BUCKET: rust-lang-gha-caches - DEPLOY_BUCKET: rust-lang-gha - TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate" - TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues" - TOOLSTATE_PUBLISH: 1 - CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5 - ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF - CACHE_DOMAIN: ci-caches-gha.rust-lang.org - if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" - strategy: - matrix: - include: - - name: dist-x86_64-apple - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - os: macos-latest - - name: dist-x86_64-apple-alt - env: - SCRIPT: "./x.py dist" - RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - os: macos-latest - - name: x86_64-apple - env: - SCRIPT: "./x.py test" - RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc" - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - os: macos-latest - timeout-minutes: 600 - runs-on: "${{ matrix.os }}" - steps: - - name: disable git crlf conversion - run: git config --global core.autocrlf false - shell: bash - - name: checkout the source code - uses: actions/checkout@v1 - with: - fetch-depth: 2 - - name: configure GitHub Actions to kill the build when outdated - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'" - - name: add extra environment variables - run: src/ci/scripts/setup-environment.sh - env: - EXTRA_VARIABLES: "${{ toJson(matrix.env) }}" - if: success() && !env.SKIP_JOB - - name: decide whether to skip this job - run: src/ci/scripts/should-skip-this.sh - if: success() && !env.SKIP_JOB - - name: collect CPU statistics - run: src/ci/scripts/collect-cpu-stats.sh - if: success() && !env.SKIP_JOB - - name: show the current environment - run: src/ci/scripts/dump-environment.sh - if: success() && !env.SKIP_JOB - - name: install awscli - run: src/ci/scripts/install-awscli.sh - if: success() && !env.SKIP_JOB - - name: install sccache - run: src/ci/scripts/install-sccache.sh - if: success() && !env.SKIP_JOB - - name: install clang - run: src/ci/scripts/install-clang.sh - if: success() && !env.SKIP_JOB - - name: install WIX - run: src/ci/scripts/install-wix.sh - if: success() && !env.SKIP_JOB - - name: install InnoSetup - run: src/ci/scripts/install-innosetup.sh - if: success() && !env.SKIP_JOB - - name: ensure the build happens on a partition with enough space - run: src/ci/scripts/symlink-build-dir.sh - if: success() && !env.SKIP_JOB - - name: disable git crlf conversion - run: src/ci/scripts/disable-git-crlf-conversion.sh - if: success() && !env.SKIP_JOB - - name: install MSYS2 - run: src/ci/scripts/install-msys2.sh - if: success() && !env.SKIP_JOB - - name: install MinGW - run: src/ci/scripts/install-mingw.sh - if: success() && !env.SKIP_JOB - - name: install ninja - run: src/ci/scripts/install-ninja.sh - if: success() && !env.SKIP_JOB - - name: enable ipv6 on Docker - run: src/ci/scripts/enable-docker-ipv6.sh - if: success() && !env.SKIP_JOB - - name: disable git crlf conversion - run: src/ci/scripts/disable-git-crlf-conversion.sh - if: success() && !env.SKIP_JOB - - name: checkout submodules - run: src/ci/scripts/checkout-submodules.sh - if: success() && !env.SKIP_JOB - - name: ensure line endings are correct - run: src/ci/scripts/verify-line-endings.sh - if: success() && !env.SKIP_JOB - - name: run the build - run: src/ci/scripts/run-build-from-ci.sh - env: - AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" - TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}" - if: success() && !env.SKIP_JOB - - name: upload artifacts to S3 - run: src/ci/scripts/upload-artifacts.sh - env: - AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}" - AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" - if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" master: name: master runs-on: ubuntu-latest diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 5e67567c76b4f..daa2d55c04399 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -414,6 +414,42 @@ jobs: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json <<: *job-linux-xl + #################### + # macOS Builders # + #################### + + - name: dist-x86_64-apple + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-xl + + - name: dist-x86_64-apple-alt + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + + - name: x86_64-apple + env: + SCRIPT: ./x.py test + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + ###################### # Windows Builders # ###################### @@ -559,51 +595,6 @@ jobs: SCRIPT: python x.py dist <<: *job-windows-xl - auto-fallible: - <<: *base-ci-job - name: auto-fallible - env: - <<: [*shared-ci-variables, *prod-variables] - if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust' - strategy: - matrix: - include: - #################### - # macOS Builders # - #################### - - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-macos-xl - - - name: dist-x86_64-apple-alt - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - - - name: x86_64-apple - env: - SCRIPT: ./x.py test - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - master: name: master runs-on: ubuntu-latest From dd346987e94fe293e9edf4b679fc75692aff1446 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Mon, 29 Jun 2020 18:06:15 +0200 Subject: [PATCH 45/92] Fix Zulip topic format --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 73ca7abfed363..51a29553fdb3d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -92,7 +92,7 @@ message_on_remove = "Issue #{number}'s prioritization request has been removed." [notify-zulip."I-nominated"] required_labels = ["T-compiler"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts -topic = "I-prioritize #{number} {title}" +topic = "I-nominated #{number} {title}" message_on_add = """\ @*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting. From 5239a68e72d1a0c7cba2cfd219a7da911360fbb7 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Sun, 21 Jun 2020 23:29:08 -0700 Subject: [PATCH 46/92] add spans to injected coverage counters added regions with counter expressions and counters. Added codegen_llvm/coverageinfo mod for upcoming coverage map Move coverage region collection to CodegenCx finalization Moved from `query coverageinfo` (renamed from `query coverage_data`), as discussed in the PR at: https://github.com/rust-lang/rust/pull/73684#issuecomment-649882503 Address merge conflict in MIR instrument_coverage test The MIR test output format changed for int types. moved debug messages out of block.rs This makes the block.rs calls to add coverage mapping data to the CodegenCx much more concise and readable. move coverage intrinsic handling into llvm impl I realized that having half of the coverage intrinsic handling in `rustc_codegen_ssa` and half in `rustc_codegen_llvm` meant that any non-llvm backend would be bound to the same decisions about how the coverage-related MIR terminators should be handled. To fix this, I moved the non-codegen portion of coverage intrinsic handling into its own trait, and implemented it in `rustc_codegen_llvm` alongside `codegen_intrinsic_call`. I also added the (required?) stubs for the new intrinsics to `IntrepretCx::emulate_intrinsic()`, to ensure calls to this function do not fail if called with these new but known intrinsics. address PR Feedback on 28 June 2020 2:48pm PDT --- src/libcore/intrinsics.rs | 35 ++++- src/librustc_codegen_llvm/base.rs | 5 + src/librustc_codegen_llvm/context.rs | 21 ++- src/librustc_codegen_llvm/coverageinfo/mod.rs | 126 +++++++++++++++++ src/librustc_codegen_llvm/intrinsic.rs | 65 ++++++++- src/librustc_codegen_llvm/lib.rs | 1 + src/librustc_codegen_ssa/coverageinfo/map.rs | 83 ++++++++++++ src/librustc_codegen_ssa/coverageinfo/mod.rs | 3 + src/librustc_codegen_ssa/lib.rs | 1 + src/librustc_codegen_ssa/mir/block.rs | 14 +- src/librustc_codegen_ssa/traits/builder.rs | 2 + .../traits/coverageinfo.rs | 35 +++++ src/librustc_codegen_ssa/traits/intrinsic.rs | 11 ++ src/librustc_codegen_ssa/traits/mod.rs | 4 + src/librustc_index/vec.rs | 3 +- src/librustc_middle/mir/coverage/mod.rs | 24 ++++ src/librustc_middle/mir/mod.rs | 28 ++-- src/librustc_middle/mir/query.rs | 14 ++ src/librustc_middle/query/mod.rs | 6 +- src/librustc_mir/interpret/intrinsics.rs | 5 +- src/librustc_mir/transform/inline.rs | 9 +- .../transform/instrument_coverage.rs | 127 ++++++++++-------- src/librustc_session/options.rs | 5 +- src/librustc_span/symbol.rs | 3 + src/librustc_typeck/check/intrinsic.rs | 12 +- .../rustc.bar.InstrumentCoverage.diff | 18 ++- .../rustc.main.InstrumentCoverage.diff | 18 ++- 27 files changed, 585 insertions(+), 93 deletions(-) create mode 100644 src/librustc_codegen_llvm/coverageinfo/mod.rs create mode 100644 src/librustc_codegen_ssa/coverageinfo/map.rs create mode 100644 src/librustc_codegen_ssa/coverageinfo/mod.rs create mode 100644 src/librustc_codegen_ssa/traits/coverageinfo.rs create mode 100644 src/librustc_middle/mir/coverage/mod.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 5d09018759191..80be8c158023d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1956,7 +1956,40 @@ extern "rust-intrinsic" { /// generation. #[cfg(not(bootstrap))] #[lang = "count_code_region"] - pub fn count_code_region(index: u32); + pub fn count_code_region(index: u32, start_byte_pos: u32, end_byte_pos: u32); + + /// Internal marker for code coverage expressions, injected into the MIR when the + /// "instrument-coverage" option is enabled. This intrinsic is not converted into a + /// backend intrinsic call, but its arguments are extracted during the production of a + /// "coverage map", which is injected into the generated code, as additional data. + /// This marker identifies a code region and two other counters or counter expressions + /// whose sum is the number of times the code region was executed. + #[cfg(not(bootstrap))] + pub fn coverage_counter_add( + index: u32, + left_index: u32, + right_index: u32, + start_byte_pos: u32, + end_byte_pos: u32, + ); + + /// This marker identifies a code region and two other counters or counter expressions + /// whose difference is the number of times the code region was executed. + /// (See `coverage_counter_add` for more information.) + #[cfg(not(bootstrap))] + pub fn coverage_counter_subtract( + index: u32, + left_index: u32, + right_index: u32, + start_byte_pos: u32, + end_byte_pos: u32, + ); + + /// This marker identifies a code region to be added to the "coverage map" to indicate source + /// code that can never be reached. + /// (See `coverage_counter_add` for more information.) + #[cfg(not(bootstrap))] + pub fn coverage_unreachable(start_byte_pos: u32, end_byte_pos: u32); /// See documentation of `<*const T>::guaranteed_eq` for details. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index e99fb8dcae1e5..d5e0d7d36ee7a 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -150,6 +150,11 @@ pub fn compile_codegen_unit( cx.create_used_variable() } + // Finalize code coverage by injecting the coverage map + if cx.sess().opts.debugging_opts.instrument_coverage { + cx.coverageinfo_finalize(); + } + // Finalize debuginfo if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 7ff5ac5cbdc10..e9a001bab7540 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -1,5 +1,6 @@ use crate::attributes; use crate::callee::get_fn; +use crate::coverageinfo; use crate::debuginfo; use crate::llvm; use crate::llvm_util; @@ -77,6 +78,7 @@ pub struct CodegenCx<'ll, 'tcx> { pub pointee_infos: RefCell, Size), Option>>, pub isize_ty: &'ll Type, + pub coverage_cx: Option>, pub dbg_cx: Option>, eh_personality: Cell>, @@ -256,6 +258,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod()); + let coverage_cx = if tcx.sess.opts.debugging_opts.instrument_coverage { + let covctx = coverageinfo::CrateCoverageContext::new(); + Some(covctx) + } else { + None + }; + let dbg_cx = if tcx.sess.opts.debuginfo != DebugInfo::None { let dctx = debuginfo::CrateDebugContext::new(llmod); debuginfo::metadata::compile_unit_metadata(tcx, &codegen_unit.name().as_str(), &dctx); @@ -285,6 +294,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { scalar_lltypes: Default::default(), pointee_infos: Default::default(), isize_ty, + coverage_cx, dbg_cx, eh_personality: Cell::new(None), rust_try_fn: Cell::new(None), @@ -296,6 +306,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { crate fn statics_to_rauw(&self) -> &RefCell> { &self.statics_to_rauw } + + #[inline] + pub fn coverage_context(&'a self) -> &'a coverageinfo::CrateCoverageContext<'tcx> { + self.coverage_cx.as_ref().unwrap() + } } impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { @@ -749,8 +764,6 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void); ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void); - ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void); - ifn!("llvm.expect.i1", fn(i1, i1) -> i1); ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); ifn!("llvm.localescape", fn(...) -> void); @@ -765,6 +778,10 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.va_end", fn(i8p) -> void); ifn!("llvm.va_copy", fn(i8p, i8p) -> void); + if self.sess().opts.debugging_opts.instrument_coverage { + ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void); + } + if self.sess().opts.debuginfo != DebugInfo::None { ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void); ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void); diff --git a/src/librustc_codegen_llvm/coverageinfo/mod.rs b/src/librustc_codegen_llvm/coverageinfo/mod.rs new file mode 100644 index 0000000000000..ff9f8f7aeaa54 --- /dev/null +++ b/src/librustc_codegen_llvm/coverageinfo/mod.rs @@ -0,0 +1,126 @@ +use crate::builder::Builder; +use crate::common::CodegenCx; +use log::debug; +use rustc_codegen_ssa::coverageinfo::map::*; +use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods}; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::Instance; + +use std::cell::RefCell; + +/// A context object for maintaining all state needed by the coverageinfo module. +pub struct CrateCoverageContext<'tcx> { + // Coverage region data for each instrumented function identified by DefId. + pub(crate) coverage_regions: RefCell, FunctionCoverageRegions>>, +} + +impl<'tcx> CrateCoverageContext<'tcx> { + pub fn new() -> Self { + Self { coverage_regions: Default::default() } + } +} + +/// Generates and exports the Coverage Map. +// FIXME(richkadel): Actually generate and export the coverage map to LLVM. +// The current implementation is actually just debug messages to show the data is available. +pub fn finalize(cx: &CodegenCx<'_, '_>) { + let coverage_regions = &*cx.coverage_context().coverage_regions.borrow(); + for instance in coverage_regions.keys() { + let coverageinfo = cx.tcx.coverageinfo(instance.def_id()); + debug_assert!(coverageinfo.num_counters > 0); + debug!( + "Generate coverage map for: {:?}, hash: {}, num_counters: {}", + instance, coverageinfo.hash, coverageinfo.num_counters + ); + let function_coverage_regions = &coverage_regions[instance]; + for (index, region) in function_coverage_regions.indexed_regions() { + match region.kind { + CoverageKind::Counter => debug!( + " Counter {}, for {}..{}", + index, region.coverage_span.start_byte_pos, region.coverage_span.end_byte_pos + ), + CoverageKind::CounterExpression(lhs, op, rhs) => debug!( + " CounterExpression {} = {} {:?} {}, for {}..{}", + index, + lhs, + op, + rhs, + region.coverage_span.start_byte_pos, + region.coverage_span.end_byte_pos + ), + } + } + for unreachable in function_coverage_regions.unreachable_regions() { + debug!( + " Unreachable code region: {}..{}", + unreachable.start_byte_pos, unreachable.end_byte_pos + ); + } + } +} + +impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> { + fn coverageinfo_finalize(&self) { + finalize(self) + } +} + +impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { + fn add_counter_region( + &mut self, + instance: Instance<'tcx>, + index: u32, + start_byte_pos: u32, + end_byte_pos: u32, + ) { + debug!( + "adding counter to coverage map: instance={:?}, index={}, byte range {}..{}", + instance, index, start_byte_pos, end_byte_pos, + ); + let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut(); + coverage_regions.entry(instance).or_default().add_counter( + index, + start_byte_pos, + end_byte_pos, + ); + } + + fn add_counter_expression_region( + &mut self, + instance: Instance<'tcx>, + index: u32, + lhs: u32, + op: CounterOp, + rhs: u32, + start_byte_pos: u32, + end_byte_pos: u32, + ) { + debug!( + "adding counter expression to coverage map: instance={:?}, index={}, {} {:?} {}, byte range {}..{}", + instance, index, lhs, op, rhs, start_byte_pos, end_byte_pos, + ); + let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut(); + coverage_regions.entry(instance).or_default().add_counter_expression( + index, + lhs, + op, + rhs, + start_byte_pos, + end_byte_pos, + ); + } + + fn add_unreachable_region( + &mut self, + instance: Instance<'tcx>, + start_byte_pos: u32, + end_byte_pos: u32, + ) { + debug!( + "adding unreachable code to coverage map: instance={:?}, byte range {}..{}", + instance, start_byte_pos, end_byte_pos, + ); + let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut(); + coverage_regions.entry(instance).or_default().add_unreachable(start_byte_pos, end_byte_pos); + } +} diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 130c0cf1877c6..de90ac0bac1d3 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -13,12 +13,15 @@ use rustc_ast::ast; use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; +use rustc_codegen_ssa::coverageinfo::CounterOp; use rustc_codegen_ssa::glue; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::MemFlags; use rustc_hir as hir; +use rustc_middle::mir::coverage; +use rustc_middle::mir::Operand; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, span_bug}; @@ -81,6 +84,53 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu } impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { + fn is_codegen_intrinsic( + &mut self, + intrinsic: &str, + args: &Vec>, + caller_instance: ty::Instance<'tcx>, + ) -> bool { + match intrinsic { + "count_code_region" => { + use coverage::count_code_region_args::*; + self.add_counter_region( + caller_instance, + op_to_u32(&args[COUNTER_INDEX]), + op_to_u32(&args[START_BYTE_POS]), + op_to_u32(&args[END_BYTE_POS]), + ); + true // Also inject the counter increment in the backend + } + "coverage_counter_add" | "coverage_counter_subtract" => { + use coverage::coverage_counter_expression_args::*; + self.add_counter_expression_region( + caller_instance, + op_to_u32(&args[COUNTER_EXPRESSION_INDEX]), + op_to_u32(&args[LEFT_INDEX]), + if intrinsic == "coverage_counter_add" { + CounterOp::Add + } else { + CounterOp::Subtract + }, + op_to_u32(&args[RIGHT_INDEX]), + op_to_u32(&args[START_BYTE_POS]), + op_to_u32(&args[END_BYTE_POS]), + ); + false // Does not inject backend code + } + "coverage_unreachable" => { + use coverage::coverage_unreachable_args::*; + self.add_unreachable_region( + caller_instance, + op_to_u32(&args[START_BYTE_POS]), + op_to_u32(&args[END_BYTE_POS]), + ); + false // Does not inject backend code + } + _ => true, // Unhandled intrinsics should be passed to `codegen_intrinsic_call()` + } + } + fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, @@ -143,15 +193,16 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { // FIXME(richkadel): The current implementation assumes the MIR for the given // caller_instance represents a single function. Validate and/or correct if inlining // and/or monomorphization invalidates these assumptions. - let coverage_data = tcx.coverage_data(caller_instance.def_id()); + let coverageinfo = tcx.coverageinfo(caller_instance.def_id()); let mangled_fn = tcx.symbol_name(caller_instance); let (mangled_fn_name, _len_val) = self.const_str(mangled_fn.name); - let hash = self.const_u64(coverage_data.hash); - let num_counters = self.const_u32(coverage_data.num_counters); - let index = args[0].immediate(); + let hash = self.const_u64(coverageinfo.hash); + let num_counters = self.const_u32(coverageinfo.num_counters); + use coverage::count_code_region_args::*; + let index = args[COUNTER_INDEX].immediate(); debug!( "count_code_region to LLVM intrinsic instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?})", - mangled_fn.name, hash, num_counters, index + mangled_fn.name, hash, num_counters, index, ); self.instrprof_increment(mangled_fn_name, hash, num_counters, index) } @@ -2131,3 +2182,7 @@ fn float_type_width(ty: Ty<'_>) -> Option { _ => None, } } + +fn op_to_u32<'tcx>(op: &Operand<'tcx>) -> u32 { + Operand::scalar_from_const(op).to_u32().expect("Scalar is u32") +} diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 55ee660d9f700..565968f9952e5 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -55,6 +55,7 @@ mod callee; mod common; mod consts; mod context; +mod coverageinfo; mod debuginfo; mod declare; mod intrinsic; diff --git a/src/librustc_codegen_ssa/coverageinfo/map.rs b/src/librustc_codegen_ssa/coverageinfo/map.rs new file mode 100644 index 0000000000000..3bd262cf2b213 --- /dev/null +++ b/src/librustc_codegen_ssa/coverageinfo/map.rs @@ -0,0 +1,83 @@ +use rustc_data_structures::fx::FxHashMap; +use std::collections::hash_map; +use std::slice; + +#[derive(Copy, Clone, Debug)] +pub enum CounterOp { + Add, + Subtract, +} + +pub enum CoverageKind { + Counter, + CounterExpression(u32, CounterOp, u32), +} + +pub struct CoverageSpan { + pub start_byte_pos: u32, + pub end_byte_pos: u32, +} + +pub struct CoverageRegion { + pub kind: CoverageKind, + pub coverage_span: CoverageSpan, +} + +/// Collects all of the coverage regions associated with (a) injected counters, (b) counter +/// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero), +/// for a given Function. Counters and counter expressions are indexed because they can be operands +/// in an expression. +/// +/// Note, it's important to distinguish the `unreachable` region type from what LLVM's refers to as +/// a "gap region" (or "gap area"). A gap region is a code region within a counted region (either +/// counter or expression), but the line or lines in the gap region are not executable (such as +/// lines with only whitespace or comments). According to LLVM Code Coverage Mapping documentation, +/// "A count for a gap area is only used as the line execution count if there are no other regions +/// on a line." +#[derive(Default)] +pub struct FunctionCoverageRegions { + indexed: FxHashMap, + unreachable: Vec, +} + +impl FunctionCoverageRegions { + pub fn add_counter(&mut self, index: u32, start_byte_pos: u32, end_byte_pos: u32) { + self.indexed.insert( + index, + CoverageRegion { + kind: CoverageKind::Counter, + coverage_span: CoverageSpan { start_byte_pos, end_byte_pos }, + }, + ); + } + + pub fn add_counter_expression( + &mut self, + index: u32, + lhs: u32, + op: CounterOp, + rhs: u32, + start_byte_pos: u32, + end_byte_pos: u32, + ) { + self.indexed.insert( + index, + CoverageRegion { + kind: CoverageKind::CounterExpression(lhs, op, rhs), + coverage_span: CoverageSpan { start_byte_pos, end_byte_pos }, + }, + ); + } + + pub fn add_unreachable(&mut self, start_byte_pos: u32, end_byte_pos: u32) { + self.unreachable.push(CoverageSpan { start_byte_pos, end_byte_pos }); + } + + pub fn indexed_regions(&self) -> hash_map::Iter<'_, u32, CoverageRegion> { + self.indexed.iter() + } + + pub fn unreachable_regions(&self) -> slice::Iter<'_, CoverageSpan> { + self.unreachable.iter() + } +} diff --git a/src/librustc_codegen_ssa/coverageinfo/mod.rs b/src/librustc_codegen_ssa/coverageinfo/mod.rs new file mode 100644 index 0000000000000..304f8e19da4e6 --- /dev/null +++ b/src/librustc_codegen_ssa/coverageinfo/mod.rs @@ -0,0 +1,3 @@ +pub mod map; + +pub use map::CounterOp; diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index bd3721850f35f..618df15f5bcbe 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -34,6 +34,7 @@ use std::path::{Path, PathBuf}; pub mod back; pub mod base; pub mod common; +pub mod coverageinfo; pub mod debuginfo; pub mod glue; pub mod meth; diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 480f9a5032087..7514eb8e889a8 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -651,6 +651,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } if intrinsic.is_some() && intrinsic != Some("drop_in_place") { + let intrinsic = intrinsic.unwrap(); + + // `is_codegen_intrinsic()` allows the backend implementation to perform compile-time + // operations before converting the `args` to backend values. + if !bx.is_codegen_intrinsic(intrinsic, &args, self.instance) { + // If the intrinsic call was fully addressed by the `is_codegen_intrinsic()` call + // (as a compile-time operation), return immediately. This avoids the need to + // convert the arguments, the call to `codegen_intrinsic_call()`, and the return + // value handling. + return; + } + let dest = match ret_dest { _ if fn_abi.ret.is_indirect() => llargs[0], ReturnDest::Nothing => { @@ -670,7 +682,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // third argument must be constant. This is // checked by const-qualification, which also // promotes any complex rvalues to constants. - if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") { + if i == 2 && intrinsic.starts_with("simd_shuffle") { if let mir::Operand::Constant(constant) = arg { let c = self.eval_mir_constant(constant); let (llval, ty) = self.simd_shuffle_indices( diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs index 7ffc9f15bffdc..994d8e0395dc7 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/src/librustc_codegen_ssa/traits/builder.rs @@ -1,5 +1,6 @@ use super::abi::AbiBuilderMethods; use super::asm::AsmBuilderMethods; +use super::coverageinfo::CoverageInfoBuilderMethods; use super::debuginfo::DebugInfoBuilderMethods; use super::intrinsic::IntrinsicCallMethods; use super::type_::ArgAbiMethods; @@ -29,6 +30,7 @@ pub enum OverflowOp { pub trait BuilderMethods<'a, 'tcx>: HasCodegen<'tcx> + + CoverageInfoBuilderMethods<'tcx> + DebugInfoBuilderMethods + ArgAbiMethods<'tcx> + AbiBuilderMethods<'tcx> diff --git a/src/librustc_codegen_ssa/traits/coverageinfo.rs b/src/librustc_codegen_ssa/traits/coverageinfo.rs new file mode 100644 index 0000000000000..d80f90fa4fa0d --- /dev/null +++ b/src/librustc_codegen_ssa/traits/coverageinfo.rs @@ -0,0 +1,35 @@ +use super::BackendTypes; +use crate::coverageinfo::CounterOp; +use rustc_middle::ty::Instance; + +pub trait CoverageInfoMethods: BackendTypes { + fn coverageinfo_finalize(&self); +} + +pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes { + fn add_counter_region( + &mut self, + instance: Instance<'tcx>, + index: u32, + start_byte_pos: u32, + end_byte_pos: u32, + ); + + fn add_counter_expression_region( + &mut self, + instance: Instance<'tcx>, + index: u32, + lhs: u32, + op: CounterOp, + rhs: u32, + start_byte_pos: u32, + end_byte_pos: u32, + ); + + fn add_unreachable_region( + &mut self, + instance: Instance<'tcx>, + start_byte_pos: u32, + end_byte_pos: u32, + ); +} diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index f62019498511c..e713cc948c10d 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -1,5 +1,6 @@ use super::BackendTypes; use crate::mir::operand::OperandRef; +use rustc_middle::mir::Operand; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; use rustc_target::abi::call::FnAbi; @@ -18,6 +19,16 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { caller_instance: ty::Instance<'tcx>, ); + /// Intrinsic-specific pre-codegen processing, if any is required. Some intrinsics are handled + /// at compile time and do not generate code. Returns true if codegen is required or false if + /// the intrinsic does not need code generation. + fn is_codegen_intrinsic( + &mut self, + intrinsic: &str, + args: &Vec>, + caller_instance: ty::Instance<'tcx>, + ) -> bool; + fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs index 6b782731d535c..0ac519dd0b17c 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/src/librustc_codegen_ssa/traits/mod.rs @@ -19,6 +19,7 @@ mod asm; mod backend; mod builder; mod consts; +mod coverageinfo; mod debuginfo; mod declare; mod intrinsic; @@ -32,6 +33,7 @@ pub use self::asm::{AsmBuilderMethods, AsmMethods, InlineAsmOperandRef}; pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; +pub use self::coverageinfo::{CoverageInfoBuilderMethods, CoverageInfoMethods}; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods}; pub use self::declare::{DeclareMethods, PreDefineMethods}; pub use self::intrinsic::IntrinsicCallMethods; @@ -56,6 +58,7 @@ pub trait CodegenMethods<'tcx>: + MiscMethods<'tcx> + ConstMethods<'tcx> + StaticMethods + + CoverageInfoMethods + DebugInfoMethods<'tcx> + DeclareMethods<'tcx> + AsmMethods @@ -72,6 +75,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + MiscMethods<'tcx> + ConstMethods<'tcx> + StaticMethods + + CoverageInfoMethods + DebugInfoMethods<'tcx> + DeclareMethods<'tcx> + AsmMethods diff --git a/src/librustc_index/vec.rs b/src/librustc_index/vec.rs index 4dde33283f575..c5dedab979326 100644 --- a/src/librustc_index/vec.rs +++ b/src/librustc_index/vec.rs @@ -536,7 +536,8 @@ impl IndexVec { } /// Create an `IndexVec` with `n` elements, where the value of each - /// element is the result of `func(i)` + /// element is the result of `func(i)`. (The underlying vector will + /// be allocated only once, with a capacity of at least `n`.) #[inline] pub fn from_fn_n(func: impl FnMut(I) -> T, n: usize) -> Self { let indices = (0..n).map(I::new); diff --git a/src/librustc_middle/mir/coverage/mod.rs b/src/librustc_middle/mir/coverage/mod.rs new file mode 100644 index 0000000000000..327f321bd7534 --- /dev/null +++ b/src/librustc_middle/mir/coverage/mod.rs @@ -0,0 +1,24 @@ +//! Metadata from source code coverage analysis and instrumentation. + +/// Positional arguments to `libcore::count_code_region()` +pub mod count_code_region_args { + pub const COUNTER_INDEX: usize = 0; + pub const START_BYTE_POS: usize = 1; + pub const END_BYTE_POS: usize = 2; +} + +/// Positional arguments to `libcore::coverage_counter_add()` and +/// `libcore::coverage_counter_subtract()` +pub mod coverage_counter_expression_args { + pub const COUNTER_EXPRESSION_INDEX: usize = 0; + pub const LEFT_INDEX: usize = 1; + pub const RIGHT_INDEX: usize = 2; + pub const START_BYTE_POS: usize = 3; + pub const END_BYTE_POS: usize = 4; +} + +/// Positional arguments to `libcore::coverage_unreachable()` +pub mod coverage_unreachable_args { + pub const START_BYTE_POS: usize = 0; + pub const END_BYTE_POS: usize = 1; +} diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 0ed0d9050078c..a3eddd3ff7ba7 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -40,6 +40,7 @@ use std::{iter, mem, option}; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; +pub mod coverage; pub mod interpret; pub mod mono; mod predecessors; @@ -2307,6 +2308,18 @@ impl<'tcx> Operand<'tcx> { }) } + /// Convenience helper to make a `Scalar` from the given `Operand`, assuming that `Operand` + /// wraps a constant literal value. Panics if this is not the case. + pub fn scalar_from_const(operand: &Operand<'tcx>) -> Scalar { + match operand { + Operand::Constant(constant) => match constant.literal.val.try_to_scalar() { + Some(scalar) => scalar, + _ => panic!("{:?}: Scalar value expected", constant.literal.val), + }, + _ => panic!("{:?}: Constant expected", operand), + } + } + pub fn to_copy(&self) -> Self { match *self { Operand::Copy(_) | Operand::Constant(_) => self.clone(), @@ -2980,18 +2993,3 @@ impl Location { } } } - -/// Coverage data associated with each function (MIR) instrumented with coverage counters, when -/// compiled with `-Zinstrument_coverage`. The query `tcx.coverage_data(DefId)` computes these -/// values on demand (during code generation). This query is only valid after executing the MIR pass -/// `InstrumentCoverage`. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] -pub struct CoverageData { - /// A hash value that can be used by the consumer of the coverage profile data to detect - /// changes to the instrumented source of the associated MIR body (typically, for an - /// individual function). - pub hash: u64, - - /// The total number of coverage region counters added to the MIR `Body`. - pub num_counters: u32, -} diff --git a/src/librustc_middle/mir/query.rs b/src/librustc_middle/mir/query.rs index 9ad79230a4f6d..8dddaf40c8264 100644 --- a/src/librustc_middle/mir/query.rs +++ b/src/librustc_middle/mir/query.rs @@ -309,3 +309,17 @@ pub struct DestructuredConst<'tcx> { pub variant: Option, pub fields: &'tcx [&'tcx ty::Const<'tcx>], } + +/// Coverage information summarized from a MIR if instrumented for source code coverage (see +/// compiler option `-Zinstrument-coverage`). This information is generated by the +/// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] +pub struct CoverageInfo { + /// A hash value that can be used by the consumer of the coverage profile data to detect + /// changes to the instrumented source of the associated MIR body (typically, for an + /// individual function). + pub hash: u64, + + /// The total number of coverage region counters added to the MIR `Body`. + pub num_counters: u32, +} diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index ba5a8c3ec2052..c9201855462ee 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -231,8 +231,10 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } - query coverage_data(key: DefId) -> mir::CoverageData { - desc { |tcx| "retrieving coverage data from MIR for `{}`", tcx.def_path_str(key) } + /// Returns coverage summary info for a function, after executing the `InstrumentCoverage` + /// MIR pass (assuming the -Zinstrument-coverage option is enabled). + query coverageinfo(key: DefId) -> mir::CoverageInfo { + desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key) } storage(ArenaCacheSelector<'tcx>) cache_on_disk_if { key.is_local() } } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 88ba28dab82e1..a2bd65e82e24e 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -410,7 +410,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.copy_op(self.operand_index(args[0], index)?, dest)?; } // FIXME(#73156): Handle source code coverage in const eval - sym::count_code_region => (), + sym::count_code_region + | sym::coverage_counter_add + | sym::coverage_counter_subtract + | sym::coverage_unreachable => (), _ => return Ok(false), } diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 068d055fa78f8..c03be2a8fcd69 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -39,7 +39,14 @@ struct CallSite<'tcx> { impl<'tcx> MirPass<'tcx> for Inline { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { - Inliner { tcx, source }.run_pass(body); + if tcx.sess.opts.debugging_opts.instrument_coverage { + // The current implementation of source code coverage injects code region counters + // into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code- + // based function. + debug!("function inlining is disabled when compiling with `instrument_coverage`"); + } else { + Inliner { tcx, source }.run_pass(body); + } } } } diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs index 06b648ab5a908..25e154f2e9597 100644 --- a/src/librustc_mir/transform/instrument_coverage.rs +++ b/src/librustc_mir/transform/instrument_coverage.rs @@ -5,65 +5,71 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::lang_items; use rustc_middle::hir; use rustc_middle::ich::StableHashingContext; -use rustc_middle::mir::interpret::{ConstValue, Scalar}; +use rustc_middle::mir::coverage::*; +use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::CoverageInfo; use rustc_middle::mir::{ - self, traversal, BasicBlock, BasicBlockData, CoverageData, Operand, Place, SourceInfo, - StatementKind, Terminator, TerminatorKind, START_BLOCK, + self, traversal, BasicBlock, BasicBlockData, Operand, Place, SourceInfo, StatementKind, + Terminator, TerminatorKind, START_BLOCK, }; use rustc_middle::ty; use rustc_middle::ty::query::Providers; +use rustc_middle::ty::FnDef; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::{ConstKind, FnDef}; use rustc_span::def_id::DefId; -use rustc_span::Span; +use rustc_span::{Pos, Span}; /// Inserts call to count_code_region() as a placeholder to be replaced during code generation with /// the intrinsic llvm.instrprof.increment. pub struct InstrumentCoverage; -/// The `query` provider for `CoverageData`, requested by `codegen_intrinsic_call()` when +/// The `query` provider for `CoverageInfo`, requested by `codegen_intrinsic_call()` when /// constructing the arguments for `llvm.instrprof.increment`. pub(crate) fn provide(providers: &mut Providers<'_>) { - providers.coverage_data = |tcx, def_id| { - let mir_body = tcx.optimized_mir(def_id); - // FIXME(richkadel): The current implementation assumes the MIR for the given DefId - // represents a single function. Validate and/or correct if inlining and/or monomorphization - // invalidates these assumptions. - let count_code_region_fn = - tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None); - let mut num_counters: u32 = 0; - // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected - // counters, with each counter having an index from `0..num_counters-1`. MIR optimization - // may split and duplicate some BasicBlock sequences. Simply counting the calls may not - // not work; but computing the num_counters by adding `1` to the highest index (for a given - // instrumented function) is valid. - for (_, data) in traversal::preorder(mir_body) { - if let Some(terminator) = &data.terminator { - if let TerminatorKind::Call { func: Operand::Constant(func), args, .. } = - &terminator.kind - { - if let FnDef(called_fn_def_id, _) = func.literal.ty.kind { - if called_fn_def_id == count_code_region_fn { - if let Operand::Constant(constant) = - args.get(0).expect("count_code_region has at least one arg") - { - if let ConstKind::Value(ConstValue::Scalar(value)) = - constant.literal.val - { - let index = value - .to_u32() - .expect("count_code_region index at arg0 is u32"); - num_counters = std::cmp::max(num_counters, index + 1); - } - } - } - } + providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id); +} + +fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> CoverageInfo { + let mir_body = tcx.optimized_mir(mir_def_id); + // FIXME(richkadel): The current implementation assumes the MIR for the given DefId + // represents a single function. Validate and/or correct if inlining (which should be disabled + // if -Zinstrument-coverage is enabled) and/or monomorphization invalidates these assumptions. + let count_code_region_fn = tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None); + + // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected + // counters, with each counter having an index from `0..num_counters-1`. MIR optimization + // may split and duplicate some BasicBlock sequences. Simply counting the calls may not + // not work; but computing the num_counters by adding `1` to the highest index (for a given + // instrumented function) is valid. + let mut num_counters: u32 = 0; + for terminator in traversal::preorder(mir_body) + .map(|(_, data)| (data, count_code_region_fn)) + .filter_map(terminators_that_call_given_fn) + { + if let TerminatorKind::Call { args, .. } = &terminator.kind { + let index_arg = args.get(count_code_region_args::COUNTER_INDEX).expect("arg found"); + let index = + mir::Operand::scalar_from_const(index_arg).to_u32().expect("index arg is u32"); + num_counters = std::cmp::max(num_counters, index + 1); + } + } + let hash = if num_counters > 0 { hash_mir_source(tcx, mir_def_id) } else { 0 }; + CoverageInfo { num_counters, hash } +} + +fn terminators_that_call_given_fn( + (data, fn_def_id): (&'tcx BasicBlockData<'tcx>, DefId), +) -> Option<&'tcx Terminator<'tcx>> { + if let Some(terminator) = &data.terminator { + if let TerminatorKind::Call { func: Operand::Constant(func), .. } = &terminator.kind { + if let FnDef(called_fn_def_id, _) = func.literal.ty.kind { + if called_fn_def_id == fn_def_id { + return Some(&terminator); } } } - let hash = if num_counters > 0 { hash_mir_source(tcx, def_id) } else { 0 }; - CoverageData { num_counters, hash } - }; + } + None } struct Instrumentor<'tcx> { @@ -102,17 +108,16 @@ impl<'tcx> Instrumentor<'tcx> { fn inject_counters(&mut self, mir_body: &mut mir::Body<'tcx>) { // FIXME(richkadel): As a first step, counters are only injected at the top of each // function. The complete solution will inject counters at each conditional code branch. - let top_of_function = START_BLOCK; - let entire_function = mir_body.span; - - self.inject_counter(mir_body, top_of_function, entire_function); + let code_region = mir_body.span; + let next_block = START_BLOCK; + self.inject_counter(mir_body, code_region, next_block); } fn inject_counter( &mut self, mir_body: &mut mir::Body<'tcx>, - next_block: BasicBlock, code_region: Span, + next_block: BasicBlock, ) { let injection_point = code_region.shrink_to_lo(); @@ -121,12 +126,20 @@ impl<'tcx> Instrumentor<'tcx> { self.tcx.require_lang_item(lang_items::CountCodeRegionFnLangItem, None), injection_point, ); - let counter_index = Operand::const_from_scalar( - self.tcx, - self.tcx.types.u32, - Scalar::from_u32(self.next_counter()), - injection_point, - ); + + let index = self.next_counter(); + + let mut args = Vec::new(); + + use count_code_region_args::*; + debug_assert_eq!(COUNTER_INDEX, args.len()); + args.push(self.const_u32(index, injection_point)); + + debug_assert_eq!(START_BYTE_POS, args.len()); + args.push(self.const_u32(code_region.lo().to_u32(), injection_point)); + + debug_assert_eq!(END_BYTE_POS, args.len()); + args.push(self.const_u32(code_region.hi().to_u32(), injection_point)); let mut patch = MirPatch::new(mir_body); @@ -136,7 +149,7 @@ impl<'tcx> Instrumentor<'tcx> { new_block, TerminatorKind::Call { func: count_code_region_fn, - args: vec![counter_index], + args, // new_block will swapped with the next_block, after applying patch destination: Some((Place::from(temp), new_block)), cleanup: None, @@ -154,6 +167,10 @@ impl<'tcx> Instrumentor<'tcx> { // `next_block`), just swap the indexes, leaving the rest of the graph unchanged. mir_body.basic_blocks_mut().swap(next_block, new_block); } + + fn const_u32(&self, value: u32, span: Span) -> Operand<'tcx> { + Operand::const_from_scalar(self.tcx, self.tcx.types.u32, Scalar::from_u32(value), span) + } } fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Operand<'tcx> { diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 9337f241d7022..f65785d15d379 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -881,8 +881,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, (default: no)"), instrument_coverage: bool = (false, parse_bool, [TRACKED], "instrument the generated code with LLVM code region counters to (in the \ - future) generate coverage reports (default: no; note, the compiler build \ - config must include `profiler = true`)"), + future) generate coverage reports; disables/overrides some optimization \ + options (note, the compiler build config must include `profiler = true`) \ + (default: no)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 857734037afe7..1159269190224 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -242,6 +242,9 @@ symbols! { core, core_intrinsics, count_code_region, + coverage_counter_add, + coverage_counter_subtract, + coverage_unreachable, crate_id, crate_in_paths, crate_local, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 1c0b22ca7370b..6205088adadb7 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -352,7 +352,17 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { return; } - "count_code_region" => (0, vec![tcx.types.u32], tcx.mk_unit()), + "count_code_region" => { + (0, vec![tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit()) + } + + "coverage_counter_add" | "coverage_counter_subtract" => ( + 0, + vec![tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32], + tcx.mk_unit(), + ), + + "coverage_unreachable" => (0, vec![tcx.types.u32, tcx.types.u32], tcx.mk_unit()), ref other => { struct_span_err!( diff --git a/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff index 8a079f0da4b01..af2899c887a94 100644 --- a/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage/rustc.bar.InstrumentCoverage.diff @@ -7,19 +7,31 @@ bb0: { + StorageLive(_1); // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 -+ _1 = const std::intrinsics::count_code_region(const 0_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 ++ _1 = const std::intrinsics::count_code_region(const 0_u32, const 484_u32, const 513_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 + // ty::Const -+ // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region} ++ // + ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region} + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/instrument_coverage.rs:18:1: 18:1 -+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar()) } ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar()) } + // ty::Const + // + ty: u32 + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/instrument_coverage.rs:18:1: 18:1 + // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x000001e4)) ++ // mir::Constant ++ // + span: $DIR/instrument_coverage.rs:18:1: 18:1 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x000001e4)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000201)) ++ // mir::Constant ++ // + span: $DIR/instrument_coverage.rs:18:1: 18:1 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000201)) } + } + + bb1 (cleanup): { diff --git a/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff index 3c2ec1dc06b70..4a300230f8a97 100644 --- a/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage/rustc.main.InstrumentCoverage.diff @@ -11,19 +11,31 @@ bb0: { - falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 + StorageLive(_4); // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 -+ _4 = const std::intrinsics::count_code_region(const 0_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 ++ _4 = const std::intrinsics::count_code_region(const 0_u32, const 387_u32, const 465_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 + // ty::Const -+ // + ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region} ++ // + ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region} + // + val: Value(Scalar()) + // mir::Constant + // + span: $DIR/instrument_coverage.rs:9:1: 9:1 -+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) {std::intrinsics::count_code_region}, val: Value(Scalar()) } ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar()) } + // ty::Const + // + ty: u32 + // + val: Value(Scalar(0x00000000)) + // mir::Constant + // + span: $DIR/instrument_coverage.rs:9:1: 9:1 + // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000183)) ++ // mir::Constant ++ // + span: $DIR/instrument_coverage.rs:9:1: 9:1 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000183)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x000001d1)) ++ // mir::Constant ++ // + span: $DIR/instrument_coverage.rs:9:1: 9:1 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x000001d1)) } } bb1: { From 334373324d9bebc6f94b3c46448494675bbc0770 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 24 Jun 2020 13:16:36 -0400 Subject: [PATCH 47/92] Serialize all foreign `SourceFile`s into proc-macro crate metadata Normally, we encode a `Span` that references a foreign `SourceFile` by encoding information about the foreign crate. When we decode this `Span`, we lookup the foreign crate in order to decode the `SourceFile`. However, this approach does not work for proc-macro crates. When we load a proc-macro crate, we do not deserialzie any of its dependencies (since a proc-macro crate can only export proc-macros). This means that we cannot serialize a reference to an upstream crate, since the associated metadata will not be available when we try to deserialize it. This commit modifies foreign span handling so that we treat all foreign `SourceFile`s as local `SourceFile`s when serializing a proc-macro. All `SourceFile`s will be stored into the metadata of a proc-macro crate, allowing us to cotinue to deserialize a proc-macro crate without needing to load any of its dependencies. Since the number of foreign `SourceFile`s that we load during a compilation session may be very large, we only serialize a `SourceFile` if we have also serialized a `Span` which requires it. --- src/librustc_metadata/rmeta/decoder.rs | 27 ++--- src/librustc_metadata/rmeta/encoder.rs | 102 +++++++++++++----- src/librustc_metadata/rmeta/mod.rs | 2 +- src/librustc_span/hygiene.rs | 3 +- src/librustc_span/source_map.rs | 43 +++++++- src/test/ui/hygiene/unpretty-debug.stdout | 4 +- .../ui/proc-macro/auxiliary/make-macro.rs | 10 ++ .../ui/proc-macro/auxiliary/meta-macro.rs | 12 +++ .../proc-macro/disappearing-resolution.stderr | 7 +- src/test/ui/proc-macro/meta-macro-hygiene.rs | 11 ++ .../ui/proc-macro/meta-macro-hygiene.stdout | 30 ++++++ src/test/ui/proc-macro/meta-macro.rs | 11 ++ src/test/ui/proc-macro/meta-macro.stdout | 1 + 13 files changed, 220 insertions(+), 43 deletions(-) create mode 100644 src/test/ui/proc-macro/auxiliary/make-macro.rs create mode 100644 src/test/ui/proc-macro/auxiliary/meta-macro.rs create mode 100644 src/test/ui/proc-macro/meta-macro-hygiene.rs create mode 100644 src/test/ui/proc-macro/meta-macro-hygiene.stdout create mode 100644 src/test/ui/proc-macro/meta-macro.rs create mode 100644 src/test/ui/proc-macro/meta-macro.stdout diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 2254d553337d5..1ac16e0d31193 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -450,19 +450,17 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { let imported_source_files = if tag == TAG_VALID_SPAN_LOCAL { self.cdata().imported_source_files(sess) } else { - // FIXME: We don't decode dependencies of proc-macros. - // Remove this once #69976 is merged + // When we encode a proc-macro crate, all `Span`s should be encoded + // with `TAG_VALID_SPAN_LOCAL` if self.cdata().root.is_proc_macro_crate() { - debug!( - "SpecializedDecoder::specialized_decode: skipping span for proc-macro crate {:?}", - self.cdata().cnum - ); // Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE // since we don't have `cnum_map` populated. - // This advances the decoder position so that we can continue - // to read metadata. - let _ = u32::decode(self)?; - return Ok(DUMMY_SP); + let cnum = u32::decode(self)?; + panic!( + "Decoding of crate {:?} tried to access proc-macro dep {:?}", + self.cdata().root.name, + cnum + ); } // tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above let cnum = CrateNum::decode(self)?; @@ -990,8 +988,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { DefKind::Macro(macro_kind(raw_macro)), self.local_def_id(def_index), ); - let ident = Ident::from_str(raw_macro.name()); - callback(Export { ident, res, vis: ty::Visibility::Public, span: DUMMY_SP }); + let ident = self.item_ident(def_index, sess); + callback(Export { + ident, + res, + vis: ty::Visibility::Public, + span: self.get_span(def_index, sess), + }); } } return; diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index d01c767e2bc04..fb4fee402abfb 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -16,6 +16,7 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor}; use rustc_hir::lang_items; use rustc_hir::{AnonConst, GenericParamKind}; +use rustc_index::bit_set::GrowableBitSet; use rustc_index::vec::Idx; use rustc_middle::hir::map::Map; use rustc_middle::middle::cstore::{EncodedMetadata, ForeignModule, LinkagePreference, NativeLib}; @@ -51,7 +52,20 @@ struct EncodeContext<'tcx> { interpret_allocs_inverse: Vec, // This is used to speed up Span encoding. - source_file_cache: Lrc, + // The `usize` is an index into the `MonotonicVec` + // that stores the `SourceFile` + source_file_cache: (Lrc, usize), + // The indices (into the `SourceMap`'s `MonotonicVec`) + // of all of the `SourceFiles` that we need to serialize. + // When we serialize a `Span`, we insert the index of its + // `SourceFile` into the `GrowableBitSet`. + // + // This needs to be a `GrowableBitSet` and not a + // regular `BitSet` because we may actually import new `SourceFiles` + // during metadata encoding, due to executing a query + // with a result containing a foreign `Span`. + required_source_files: Option>, + is_proc_macro: bool, } macro_rules! encoder_methods { @@ -154,18 +168,23 @@ impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { // The Span infrastructure should make sure that this invariant holds: debug_assert!(span.lo <= span.hi); - if !self.source_file_cache.contains(span.lo) { + if !self.source_file_cache.0.contains(span.lo) { let source_map = self.tcx.sess.source_map(); let source_file_index = source_map.lookup_source_file_idx(span.lo); - self.source_file_cache = source_map.files()[source_file_index].clone(); + self.source_file_cache = + (source_map.files()[source_file_index].clone(), source_file_index); } - if !self.source_file_cache.contains(span.hi) { + if !self.source_file_cache.0.contains(span.hi) { // Unfortunately, macro expansion still sometimes generates Spans // that malformed in this way. return TAG_INVALID_SPAN.encode(self); } + let source_files = self.required_source_files.as_mut().expect("Already encoded SourceMap!"); + // Record the fact that we need to encode the data for this `SourceFile` + source_files.insert(self.source_file_cache.1); + // There are two possible cases here: // 1. This span comes from a 'foreign' crate - e.g. some crate upstream of the // crate we are writing metadata for. When the metadata for *this* crate gets @@ -176,7 +195,13 @@ impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { // 2. This span comes from our own crate. No special hamdling is needed - we just // write `TAG_VALID_SPAN_LOCAL` to let the deserializer know that it should use // our own source map information. - let (tag, lo, hi) = if self.source_file_cache.is_imported() { + // + // If we're a proc-macro crate, we always treat this as a local `Span`. + // In `encode_source_map`, we serialize foreign `SourceFile`s into our metadata + // if we're a proc-macro crate. + // This allows us to avoid loading the dependencies of proc-macro crates: all of + // the information we need to decode `Span`s is stored in the proc-macro crate. + let (tag, lo, hi) = if self.source_file_cache.0.is_imported() && !self.is_proc_macro { // To simplify deserialization, we 'rebase' this span onto the crate it originally came from // (the crate that 'owns' the file it references. These rebased 'lo' and 'hi' values // are relative to the source map information for the 'foreign' crate whose CrateNum @@ -188,13 +213,13 @@ impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { // Span that can be used without any additional trouble. let external_start_pos = { // Introduce a new scope so that we drop the 'lock()' temporary - match &*self.source_file_cache.external_src.lock() { + match &*self.source_file_cache.0.external_src.lock() { ExternalSource::Foreign { original_start_pos, .. } => *original_start_pos, src => panic!("Unexpected external source {:?}", src), } }; - let lo = (span.lo - self.source_file_cache.start_pos) + external_start_pos; - let hi = (span.hi - self.source_file_cache.start_pos) + external_start_pos; + let lo = (span.lo - self.source_file_cache.0.start_pos) + external_start_pos; + let hi = (span.hi - self.source_file_cache.0.start_pos) + external_start_pos; (TAG_VALID_SPAN_FOREIGN, lo, hi) } else { @@ -212,7 +237,7 @@ impl<'tcx> SpecializedEncoder for EncodeContext<'tcx> { if tag == TAG_VALID_SPAN_FOREIGN { // This needs to be two lines to avoid holding the `self.source_file_cache` // while calling `cnum.encode(self)` - let cnum = self.source_file_cache.cnum; + let cnum = self.source_file_cache.0.cnum; cnum.encode(self)?; } Ok(()) @@ -386,17 +411,24 @@ impl<'tcx> EncodeContext<'tcx> { let all_source_files = source_map.files(); let (working_dir, _cwd_remapped) = self.tcx.sess.working_dir.clone(); + // By replacing the `Option` with `None`, we ensure that we can't + // accidentally serialize any more `Span`s after the source map encoding + // is done. + let required_source_files = self.required_source_files.take().unwrap(); let adapted = all_source_files .iter() - .filter(|source_file| { - // No need to re-export imported source_files, as any downstream - // crate will import them from their original source. - // FIXME(eddyb) the `Span` encoding should take that into account. - !source_file.is_imported() + .enumerate() + .filter(|(idx, source_file)| { + // Only serialize `SourceFile`s that were used + // during the encoding of a `Span` + required_source_files.contains(*idx) && + // Don't serialize imported `SourceFile`s, unless + // we're in a proc-macro crate. + (!source_file.is_imported() || self.is_proc_macro) }) - .map(|source_file| { - match source_file.name { + .map(|(_, source_file)| { + let mut adapted = match source_file.name { // This path of this SourceFile has been modified by // path-remapping, so we use it verbatim (and avoid // cloning the whole map in the process). @@ -419,15 +451,30 @@ impl<'tcx> EncodeContext<'tcx> { // expanded code, not from a file _ => source_file.clone(), + }; + + // We're serializing this `SourceFile` into our crate metadata, + // so mark it as coming from this crate. + // This also ensures that we don't try to deserialize the + // `CrateNum` for a proc-macro dependency - since proc macro + // dependencies aren't loaded when we deserialize a proc-macro, + // trying to remap the `CrateNum` would fail. + if self.is_proc_macro { + Lrc::make_mut(&mut adapted).cnum = LOCAL_CRATE; } + adapted }) .collect::>(); self.lazy(adapted.iter().map(|rc| &**rc)) } + fn is_proc_macro(&self) -> bool { + self.tcx.sess.crate_types().contains(&CrateType::ProcMacro) + } + fn encode_crate_root(&mut self) -> Lazy> { - let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro); + let is_proc_macro = self.is_proc_macro(); let mut i = self.position(); @@ -458,11 +505,6 @@ impl<'tcx> EncodeContext<'tcx> { let foreign_modules = self.encode_foreign_modules(); - // Encode source_map - i = self.position(); - let source_map = self.encode_source_map(); - let source_map_bytes = self.position() - i; - // Encode DefPathTable i = self.position(); let def_path_table = self.encode_def_path_table(); @@ -514,12 +556,19 @@ impl<'tcx> EncodeContext<'tcx> { let proc_macro_data_bytes = self.position() - i; // Encode exported symbols info. This is prefetched in `encode_metadata` so we encode - // this last to give the prefetching as much time as possible to complete. + // this late to give the prefetching as much time as possible to complete. i = self.position(); let exported_symbols = self.tcx.exported_symbols(LOCAL_CRATE); let exported_symbols = self.encode_exported_symbols(&exported_symbols); let exported_symbols_bytes = self.position() - i; + // Encode source_map. This needs to be done last, + // since encoding `Span`s tells us which `SourceFiles` we actually + // need to encode. + i = self.position(); + let source_map = self.encode_source_map(); + let source_map_bytes = self.position() - i; + let attrs = tcx.hir().krate_attrs(); let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator); @@ -1854,6 +1903,8 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { // Will be filled with the root position after encoding everything. encoder.emit_raw_bytes(&[0, 0, 0, 0]); + let source_map_files = tcx.sess.source_map().files(); + let mut ecx = EncodeContext { opaque: encoder, tcx, @@ -1861,10 +1912,13 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default(), - source_file_cache: tcx.sess.source_map().files()[0].clone(), + source_file_cache: (source_map_files[0].clone(), 0), interpret_allocs: Default::default(), interpret_allocs_inverse: Default::default(), + required_source_files: Some(GrowableBitSet::with_capacity(source_map_files.len())), + is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro), }; + drop(source_map_files); // Encode the rustc version string in a predictable location. rustc_version().encode(&mut ecx).unwrap(); diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 381e7ee115e17..8abc3784d6d2f 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -192,7 +192,6 @@ crate struct CrateRoot<'tcx> { diagnostic_items: Lazy<[(Symbol, DefIndex)]>, native_libraries: Lazy<[NativeLib]>, foreign_modules: Lazy<[ForeignModule]>, - source_map: Lazy<[rustc_span::SourceFile]>, def_path_table: Lazy, impls: Lazy<[TraitImpls]>, interpret_alloc_index: Lazy<[u32]>, @@ -203,6 +202,7 @@ crate struct CrateRoot<'tcx> { proc_macro_data: Option>, exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]), + source_map: Lazy<[rustc_span::SourceFile]>, compiler_builtins: bool, needs_allocator: bool, diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs index 60bbdd0495cc4..90f4cc0966080 100644 --- a/src/librustc_span/hygiene.rs +++ b/src/librustc_span/hygiene.rs @@ -395,10 +395,11 @@ pub fn debug_hygiene_data(verbose: bool) -> String { data.expn_data.iter().enumerate().for_each(|(id, expn_info)| { let expn_info = expn_info.as_ref().expect("no expansion data for an expansion ID"); s.push_str(&format!( - "\n{}: parent: {:?}, call_site_ctxt: {:?}, kind: {:?}", + "\n{}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}", id, expn_info.parent, expn_info.call_site.ctxt(), + expn_info.def_site.ctxt(), expn_info.kind, )); }); diff --git a/src/librustc_span/source_map.rs b/src/librustc_span/source_map.rs index 4b5bce1db2628..e062c7766e7dc 100644 --- a/src/librustc_span/source_map.rs +++ b/src/librustc_span/source_map.rs @@ -40,6 +40,41 @@ pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { } } +pub mod monotonic { + use std::ops::{Deref, DerefMut}; + + /// A `MonotonicVec` is a `Vec` which can only be grown. + /// Once inserted, an element can never be removed or swapped, + /// guaranteeing that any indices into a `MonotonicVec` are stable + // This is declared in its own module to ensure that the private + // field is inaccessible + pub struct MonotonicVec(Vec); + impl MonotonicVec { + pub fn new(val: Vec) -> MonotonicVec { + MonotonicVec(val) + } + + pub fn push(&mut self, val: T) { + self.0.push(val); + } + } + + impl Default for MonotonicVec { + fn default() -> Self { + MonotonicVec::new(vec![]) + } + } + + impl Deref for MonotonicVec { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl !DerefMut for MonotonicVec {} +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, HashStable_Generic)] pub struct Spanned { pub node: T, @@ -125,7 +160,7 @@ impl StableSourceFileId { #[derive(Default)] pub(super) struct SourceMapFiles { - source_files: Vec>, + source_files: monotonic::MonotonicVec>, stable_id_to_source_file: FxHashMap>, } @@ -199,7 +234,9 @@ impl SourceMap { Ok(bytes) } - pub fn files(&self) -> MappedLockGuard<'_, Vec>> { + // By returning a `MonotonicVec`, we ensure that consumers cannot invalidate + // any existing indices pointing into `files`. + pub fn files(&self) -> MappedLockGuard<'_, monotonic::MonotonicVec>> { LockGuard::map(self.files.borrow(), |files| &mut files.source_files) } @@ -912,6 +949,8 @@ impl SourceMap { } // Returns the index of the `SourceFile` (in `self.files`) that contains `pos`. + // This index is guaranteed to be valid for the lifetime of this `SourceMap`, + // since `source_files` is a `MonotonicVec` pub fn lookup_source_file_idx(&self, pos: BytePos) -> usize { self.files .borrow() diff --git a/src/test/ui/hygiene/unpretty-debug.stdout b/src/test/ui/hygiene/unpretty-debug.stdout index acd852103cae3..81164030d8eef 100644 --- a/src/test/ui/hygiene/unpretty-debug.stdout +++ b/src/test/ui/hygiene/unpretty-debug.stdout @@ -16,8 +16,8 @@ fn y /* 0#0 */() { } /* Expansions: -0: parent: ExpnId(0), call_site_ctxt: #0, kind: Root -1: parent: ExpnId(0), call_site_ctxt: #0, kind: Macro(Bang, "foo") +0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "foo") SyntaxContexts: #0: parent: #0, outer_mark: (ExpnId(0), Opaque) diff --git a/src/test/ui/proc-macro/auxiliary/make-macro.rs b/src/test/ui/proc-macro/auxiliary/make-macro.rs new file mode 100644 index 0000000000000..155d54ea0bfb0 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/make-macro.rs @@ -0,0 +1,10 @@ +#[macro_export] +macro_rules! make_it { + ($name:ident) => { + #[proc_macro] + pub fn $name(input: TokenStream) -> TokenStream { + println!("Def site: {:?}", Span::def_site()); + input + } + }; +} diff --git a/src/test/ui/proc-macro/auxiliary/meta-macro.rs b/src/test/ui/proc-macro/auxiliary/meta-macro.rs new file mode 100644 index 0000000000000..5265c6533b479 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/meta-macro.rs @@ -0,0 +1,12 @@ +// force-host +// no-prefer-dynamic +// edition:2018 + +#![feature(proc_macro_def_site)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +extern crate make_macro; +use proc_macro::{TokenStream, Span}; + +make_macro::make_it!(print_def_site); diff --git a/src/test/ui/proc-macro/disappearing-resolution.stderr b/src/test/ui/proc-macro/disappearing-resolution.stderr index ff7ddcde6e0c4..5b969549a117c 100644 --- a/src/test/ui/proc-macro/disappearing-resolution.stderr +++ b/src/test/ui/proc-macro/disappearing-resolution.stderr @@ -10,11 +10,16 @@ error[E0603]: derive macro import `Empty` is private LL | use m::Empty; | ^^^^^ private derive macro import | -note: the derive macro import `Empty` is defined here +note: the derive macro import `Empty` is defined here... --> $DIR/disappearing-resolution.rs:9:9 | LL | use test_macros::Empty; | ^^^^^^^^^^^^^^^^^^ +note: ...and refers to the derive macro `Empty` which is defined here + --> $DIR/auxiliary/test-macros.rs:25:1 + | +LL | pub fn empty_derive(_: TokenStream) -> TokenStream { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider importing it directly error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.rs b/src/test/ui/proc-macro/meta-macro-hygiene.rs new file mode 100644 index 0000000000000..97401448911a3 --- /dev/null +++ b/src/test/ui/proc-macro/meta-macro-hygiene.rs @@ -0,0 +1,11 @@ +// aux-build:make-macro.rs +// aux-build:meta-macro.rs +// edition:2018 +// compile-flags: -Z span-debug -Z unpretty=expanded,hygiene +// check-pass + +extern crate meta_macro; + +fn main() { + meta_macro::print_def_site!(); +} diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout new file mode 100644 index 0000000000000..b3a20763dc5e6 --- /dev/null +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -0,0 +1,30 @@ +Def site: $DIR/auxiliary/make-macro.rs:5:9: 8:10 (#3) +#![feature /* 280#0 */(prelude_import)] +#[prelude_import /* 527#1 */] +use std /* 687#1 */::prelude /* 526#1 */::v1 /* 783#1 */::*; +#[macro_use /* 404#1 */] +extern crate std /* 687#1 */; +// aux-build:make-macro.rs +// aux-build:meta-macro.rs +// edition:2018 +// compile-flags: -Z span-debug -Z unpretty=expanded,hygiene +// check-pass + +extern crate meta_macro /* 834#0 */; + +fn main /* 406#0 */() { } + +/* +Expansions: +0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root +1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) +2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") + +SyntaxContexts: +#0: parent: #0, outer_mark: (ExpnId(0), Opaque) +#1: parent: #0, outer_mark: (ExpnId(1), Opaque) +#2: parent: #0, outer_mark: (ExpnId(1), Transparent) +#3: parent: #0, outer_mark: (ExpnId(2), Opaque) +#4: parent: #0, outer_mark: (ExpnId(2), Transparent) +#5: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) +*/ diff --git a/src/test/ui/proc-macro/meta-macro.rs b/src/test/ui/proc-macro/meta-macro.rs new file mode 100644 index 0000000000000..dbfde9e113f37 --- /dev/null +++ b/src/test/ui/proc-macro/meta-macro.rs @@ -0,0 +1,11 @@ +// aux-build:make-macro.rs +// aux-build:meta-macro.rs +// edition:2018 +// compile-flags: -Z span-debug +// run-pass + +extern crate meta_macro; + +fn main() { + meta_macro::print_def_site!(); +} diff --git a/src/test/ui/proc-macro/meta-macro.stdout b/src/test/ui/proc-macro/meta-macro.stdout new file mode 100644 index 0000000000000..00439bc292081 --- /dev/null +++ b/src/test/ui/proc-macro/meta-macro.stdout @@ -0,0 +1 @@ +Def site: $DIR/auxiliary/make-macro.rs:5:9: 8:10 (#3) From a7c408d6ac74f4fef732d740e95e1d2504613bb6 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 29 Jun 2020 22:02:57 -0400 Subject: [PATCH 48/92] Normalize symbol ids to 0 in test stdout The number of symbols we allocate (even early on) seems to be platform dependent. We only care about hygiene for the purposes of this test, so just set all of the symbol ids to zero --- src/test/ui/proc-macro/meta-macro-hygiene.rs | 4 +++- .../ui/proc-macro/meta-macro-hygiene.stdout | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.rs b/src/test/ui/proc-macro/meta-macro-hygiene.rs index 97401448911a3..449377aed993e 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.rs +++ b/src/test/ui/proc-macro/meta-macro-hygiene.rs @@ -3,7 +3,9 @@ // edition:2018 // compile-flags: -Z span-debug -Z unpretty=expanded,hygiene // check-pass - +// normalize-stdout-test "\d+#" -> "0#" +// ^ We don't care about symbol ids, so set them all to 0 +// in the stdout extern crate meta_macro; fn main() { diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index b3a20763dc5e6..acff85bd6b233 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,18 +1,20 @@ Def site: $DIR/auxiliary/make-macro.rs:5:9: 8:10 (#3) -#![feature /* 280#0 */(prelude_import)] -#[prelude_import /* 527#1 */] -use std /* 687#1 */::prelude /* 526#1 */::v1 /* 783#1 */::*; -#[macro_use /* 404#1 */] -extern crate std /* 687#1 */; +#![feature /* 0#0 */(prelude_import)] +#[prelude_import /* 0#1 */] +use std /* 0#1 */::prelude /* 0#1 */::v1 /* 0#1 */::*; +#[macro_use /* 0#1 */] +extern crate std /* 0#1 */; // aux-build:make-macro.rs // aux-build:meta-macro.rs // edition:2018 // compile-flags: -Z span-debug -Z unpretty=expanded,hygiene // check-pass +// normalize-stdout-test "\d+#" -> "0#" +// ^ We don't care about symbol ids, so set them all to 0 +// in the stdout +extern crate meta_macro /* 0#0 */; -extern crate meta_macro /* 834#0 */; - -fn main /* 406#0 */() { } +fn main /* 0#0 */() { } /* Expansions: From 915486364759689dce6932d67599d5ea234cd91a Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 28 Jun 2020 11:55:50 -0700 Subject: [PATCH 49/92] Compile rustdoc less often. --- src/bootstrap/doc.rs | 14 +++++----- src/bootstrap/test.rs | 60 +++++++++++++++++++++++++++++++++---------- src/bootstrap/tool.rs | 6 ++--- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 8b76158f9e564..6d781c8e45607 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -518,8 +518,7 @@ impl Step for Rustc { let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); - // Get the correct compiler for this stage. - let compiler = builder.compiler_for(stage, builder.config.build, target); + let compiler = builder.compiler(stage, builder.config.build); if !builder.config.compiler_docs { builder.info("\tskipping - compiler/librustdoc docs disabled"); @@ -599,8 +598,7 @@ impl Step for Rustdoc { let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); - // Get the correct compiler for this stage. - let compiler = builder.compiler_for(stage, builder.config.build, target); + let compiler = builder.compiler(stage, builder.config.build); if !builder.config.compiler_docs { builder.info("\tskipping - compiler/librustdoc docs disabled"); @@ -666,15 +664,15 @@ impl Step for ErrorIndex { builder.info(&format!("Documenting error index ({})", target)); let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(2, builder.config.build); + // error_index_generator depends on librustdoc. Use the compiler that + // is normally used to build rustdoc for other documentation so that + // it shares the same artifacts. + let compiler = builder.compiler_for(builder.top_stage, builder.config.build, target); let mut index = tool::ErrorIndex::command(builder, compiler); index.arg("html"); index.arg(out.join("error-index.html")); index.arg(crate::channel::CFG_RELEASE_NUM); - // FIXME: shouldn't have to pass this env var - index.env("CFG_BUILD", &builder.config.build); - builder.run(&mut index); } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 12ab6b1636cc1..77bcc00d75b2b 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1454,8 +1454,11 @@ impl Step for ErrorIndex { } fn make_run(run: RunConfig<'_>) { - run.builder - .ensure(ErrorIndex { compiler: run.builder.compiler(run.builder.top_stage, run.host) }); + // error_index_generator depends on librustdoc. Use the compiler that + // is normally used to build rustdoc for other tests (like compiletest + // tests in src/test/rustdoc) so that it shares the same artifacts. + let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); + run.builder.ensure(ErrorIndex { compiler }); } /// Runs the error index generator tool to execute the tests located in the error @@ -1467,22 +1470,23 @@ impl Step for ErrorIndex { fn run(self, builder: &Builder<'_>) { let compiler = self.compiler; - builder.ensure(compile::Std { compiler, target: compiler.host }); - let dir = testdir(builder, compiler.host); t!(fs::create_dir_all(&dir)); let output = dir.join("error-index.md"); - let mut tool = tool::ErrorIndex::command( - builder, - builder.compiler(compiler.stage, builder.config.build), - ); - tool.arg("markdown").arg(&output).env("CFG_BUILD", &builder.config.build); + let mut tool = tool::ErrorIndex::command(builder, compiler); + tool.arg("markdown").arg(&output); - builder.info(&format!("Testing error-index stage{}", compiler.stage)); + // Use the rustdoc that was built by self.compiler. This copy of + // rustdoc is shared with other tests (like compiletest tests in + // src/test/rustdoc). This helps avoid building rustdoc multiple + // times. + let rustdoc_compiler = builder.compiler(builder.top_stage, builder.config.build); + builder.info(&format!("Testing error-index stage{}", rustdoc_compiler.stage)); let _time = util::timeit(&builder); builder.run_quiet(&mut tool); - markdown_test(builder, compiler, &output); + builder.ensure(compile::Std { compiler: rustdoc_compiler, target: rustdoc_compiler.host }); + markdown_test(builder, rustdoc_compiler, &output); } } @@ -1797,9 +1801,13 @@ impl Step for CrateRustdoc { fn run(self, builder: &Builder<'_>) { let test_kind = self.test_kind; + let target = self.host; - let compiler = builder.compiler(builder.top_stage, self.host); - let target = compiler.host; + // Use the previous stage compiler to reuse the artifacts that are + // created when running compiletest for src/test/rustdoc. If this used + // `compiler`, then it would cause rustdoc to be built *again*, which + // isn't really necessary. + let compiler = builder.compiler_for(builder.top_stage, target, target); builder.ensure(compile::Rustc { compiler, target }); let mut cargo = tool::prepare_tool_cargo( @@ -1825,6 +1833,32 @@ impl Step for CrateRustdoc { cargo.arg("'-Ctarget-feature=-crt-static'"); } + // This is needed for running doctests on librustdoc. This is a bit of + // an unfortunate interaction with how bootstrap works and how cargo + // sets up the dylib path, and the fact that the doctest (in + // html/markdown.rs) links to rustc-private libs. For stage1, the + // compiler host dylibs (in stage1/lib) are not the same as the target + // dylibs (in stage1/lib/rustlib/...). This is different from a normal + // rust distribution where they are the same. + // + // On the cargo side, normal tests use `target_process` which handles + // setting up the dylib for a *target* (stage1/lib/rustlib/... in this + // case). However, for doctests it uses `rustdoc_process` which only + // sets up the dylib path for the *host* (stage1/lib), which is the + // wrong directory. + // + // It should be considered to just stop running doctests on + // librustdoc. There is only one test, and it doesn't look too + // important. There might be other ways to avoid this, but it seems + // pretty convoluted. + // + // See also https://github.com/rust-lang/rust/issues/13983 where the + // host vs target dylibs for rustdoc are consistently tricky to deal + // with. + let mut dylib_path = dylib_path(); + dylib_path.insert(0, PathBuf::from(&*builder.sysroot_libdir(compiler, target))); + cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + if !builder.config.verbose_tests { cargo.arg("--quiet"); } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 063fb8fbb9526..b3fa3b49855fd 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -392,9 +392,9 @@ impl Step for ErrorIndex { fn make_run(run: RunConfig<'_>) { // Compile the error-index in the same stage as rustdoc to avoid // recompiling rustdoc twice if we can. - let stage = if run.builder.top_stage >= 2 { run.builder.top_stage } else { 0 }; - run.builder - .ensure(ErrorIndex { compiler: run.builder.compiler(stage, run.builder.config.build) }); + let host = run.builder.config.build; + let compiler = run.builder.compiler_for(run.builder.top_stage, host, host); + run.builder.ensure(ErrorIndex { compiler }); } fn run(self, builder: &Builder<'_>) -> PathBuf { From 844dc31494ad130169477c57c9ba10acd5e8923f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Tue, 30 Jun 2020 09:13:15 +0200 Subject: [PATCH 50/92] ci: fix wasm32 broken due to a NodeJS version bump Emscripten's SDK recently bumped the version of NodeJS they shipped, but our Dockerfile for the wasm32 builder hardcoded the version number. This will cause consistent CI failures once the currently cached image is rebuilt (either due to a change or due to the cache expiring). This commit fixes the problem by finding the latest version of NodeJS in the Emscripten SDK and symlinking it to a "latest" directory, which is then added to the PATH. --- src/ci/docker/wasm32/Dockerfile | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/wasm32/Dockerfile b/src/ci/docker/wasm32/Dockerfile index 8232539edda77..92461305320ee 100644 --- a/src/ci/docker/wasm32/Dockerfile +++ b/src/ci/docker/wasm32/Dockerfile @@ -25,7 +25,18 @@ RUN ln `which python3` /usr/bin/python ENV PATH=$PATH:/emsdk-portable ENV PATH=$PATH:/emsdk-portable/upstream/emscripten/ -ENV PATH=$PATH:/emsdk-portable/node/12.9.1_64bit/bin/ + +# Rust's build system requires NodeJS to be in the path, but the directory in +# which emsdk stores it contains the version number. This caused breakages in +# the past when emsdk bumped the node version causing the path to point to a +# missing directory. +# +# To avoid the problem this symlinks the latest NodeJs version available to +# "latest", and adds that to the path. +RUN ln -s /emsdk-portable/node/$(ls /emsdk-portable/node | sort -V | tail -n 1) \ + /emsdk-portable/node/latest +ENV PATH=$PATH:/emsdk-portable/node/latest/bin/ + ENV BINARYEN_ROOT=/emsdk-portable/upstream/ ENV EMSDK=/emsdk-portable ENV EM_CONFIG=/emsdk-portable/.emscripten From 1d7ba5fcb40362e0c1802a228efbb8dde7f5711d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 24 Jun 2020 23:14:18 +0200 Subject: [PATCH 51/92] stop taking references in Relate --- src/librustc_infer/infer/at.rs | 18 +- .../infer/canonical/query_response.rs | 4 +- src/librustc_infer/infer/combine.rs | 22 +- src/librustc_infer/infer/equate.rs | 12 +- src/librustc_infer/infer/glb.rs | 12 +- src/librustc_infer/infer/higher_ranked/mod.rs | 10 +- src/librustc_infer/infer/lub.rs | 14 +- src/librustc_infer/infer/nll_relate/mod.rs | 44 ++-- src/librustc_infer/infer/sub.rs | 8 +- src/librustc_middle/ty/_match.rs | 10 +- src/librustc_middle/ty/relate.rs | 226 +++++++----------- .../borrow_check/type_check/relate_tys.rs | 2 +- .../traits/select/mod.rs | 8 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/dropck.rs | 18 +- 15 files changed, 182 insertions(+), 228 deletions(-) diff --git a/src/librustc_infer/infer/at.rs b/src/librustc_infer/infer/at.rs index d44b8f554143c..a7749d33b7c13 100644 --- a/src/librustc_infer/infer/at.rs +++ b/src/librustc_infer/infer/at.rs @@ -82,7 +82,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace_exp(a_is_expected, a, b).sub(&a, &b) + self.trace_exp(a_is_expected, a, b).sub(a, b) } /// Makes `actual <: expected`. For example, if type-checking a @@ -109,7 +109,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace_exp(a_is_expected, a, b).eq(&a, &b) + self.trace_exp(a_is_expected, a, b).eq(a, b) } /// Makes `expected <: actual`. @@ -117,7 +117,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).eq(&expected, &actual) + self.trace(expected, actual).eq(expected, actual) } pub fn relate(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()> @@ -147,7 +147,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).lub(&expected, &actual) + self.trace(expected, actual).lub(expected, actual) } /// Computes the greatest-lower-bound, or mutual subtype, of two @@ -157,7 +157,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - self.trace(expected, actual).glb(&expected, &actual) + self.trace(expected, actual).glb(expected, actual) } /// Sets the "trace" values that will be used for @@ -186,7 +186,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a <: b` where `a` may or may not be expected (if /// `a_is_expected` is true, then `a` is expected). - pub fn sub(self, a: &T, b: &T) -> InferResult<'tcx, ()> + pub fn sub(self, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { @@ -203,7 +203,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { /// Makes `a == b`; the expectation is set by the call to /// `trace()`. - pub fn eq(self, a: &T, b: &T) -> InferResult<'tcx, ()> + pub fn eq(self, a: T, b: T) -> InferResult<'tcx, ()> where T: Relate<'tcx>, { @@ -218,7 +218,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { }) } - pub fn lub(self, a: &T, b: &T) -> InferResult<'tcx, T> + pub fn lub(self, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { @@ -233,7 +233,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> { }) } - pub fn glb(self, a: &T, b: &T) -> InferResult<'tcx, T> + pub fn glb(self, a: T, b: T) -> InferResult<'tcx, T> where T: Relate<'tcx>, { diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index 8af526e3ad31b..a6d7b403fe7a9 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -271,7 +271,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { }, ty::Variance::Invariant, ) - .relate(&v1, &v2)?; + .relate(v1, v2)?; } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { @@ -285,7 +285,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { }, ty::Variance::Invariant, ) - .relate(&v1, &v2)?; + .relate(v1, v2)?; } _ => { diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 4ef4ed47cb11a..fa54d815055ec 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -318,10 +318,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // to associate causes/spans with each of the relations in // the stack to get this right. match dir { - EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), - SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), + EqTo => self.equate(a_is_expected).relate(a_ty, b_ty), + SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty), SupertypeOf => { - self.sub(a_is_expected).relate_with_variance(ty::Contravariant, &a_ty, &b_ty) + self.sub(a_is_expected).relate_with_variance(ty::Contravariant, a_ty, b_ty) } }?; @@ -379,7 +379,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { param_env: self.param_env, }; - let ty = match generalize.relate(&ty, &ty) { + let ty = match generalize.relate(ty, ty) { Ok(ty) => ty, Err(e) => { debug!("generalize: failure {:?}", e); @@ -490,13 +490,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(ty::Binder::bind(self.relate(*a.skip_binder(), *b.skip_binder())?)) } fn relate_item_substs( @@ -519,8 +519,8 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn relate_with_variance>( &mut self, variance: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { let old_ambient_variance = self.ambient_variance; self.ambient_variance = self.ambient_variance.xform(variance); @@ -552,7 +552,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { match probe { TypeVariableValue::Known { value: u } => { debug!("generalize: known value {:?}", u); - self.relate(&u, &u) + self.relate(u, u) } TypeVariableValue::Unknown { universe } => { match self.ambient_variance { @@ -655,7 +655,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { let variable_table = &mut inner.const_unification_table(); let var_value = variable_table.probe_value(vid); match var_value.val { - ConstVariableValue::Known { value: u } => self.relate(&u, &u), + ConstVariableValue::Known { value: u } => self.relate(u, u), ConstVariableValue::Unknown { universe } => { if self.for_universe.can_name(universe) { Ok(c) diff --git a/src/librustc_infer/infer/equate.rs b/src/librustc_infer/infer/equate.rs index e3cafb82719dd..6826956b38bd8 100644 --- a/src/librustc_infer/infer/equate.rs +++ b/src/librustc_infer/infer/equate.rs @@ -59,8 +59,8 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { fn relate_with_variance>( &mut self, _: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { self.relate(a, b) } @@ -124,8 +124,8 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, @@ -135,8 +135,8 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { self.fields.higher_ranked_sub(b, a, self.a_is_expected) } else { // Fast path for the common case. - self.relate(a.skip_binder(), b.skip_binder())?; - Ok(a.clone()) + self.relate(*a.skip_binder(), *b.skip_binder())?; + Ok(a) } } } diff --git a/src/librustc_infer/infer/glb.rs b/src/librustc_infer/infer/glb.rs index ec219a95b9441..8a0ab52f38306 100644 --- a/src/librustc_infer/infer/glb.rs +++ b/src/librustc_infer/infer/glb.rs @@ -43,8 +43,8 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { fn relate_with_variance>( &mut self, variance: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), @@ -85,8 +85,8 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, @@ -112,8 +112,8 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(self.a_is_expected); - sub.relate(&v, &a)?; - sub.relate(&v, &b)?; + sub.relate(v, a)?; + sub.relate(v, b)?; Ok(()) } } diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/src/librustc_infer/infer/higher_ranked/mod.rs index b6251e34008a3..ea19dff7db125 100644 --- a/src/librustc_infer/infer/higher_ranked/mod.rs +++ b/src/librustc_infer/infer/higher_ranked/mod.rs @@ -11,8 +11,8 @@ use rustc_middle::ty::{self, Binder, TypeFoldable}; impl<'a, 'tcx> CombineFields<'a, 'tcx> { pub fn higher_ranked_sub( &mut self, - a: &Binder, - b: &Binder, + a: Binder, + b: Binder, a_is_expected: bool, ) -> RelateResult<'tcx, Binder> where @@ -33,20 +33,20 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { self.infcx.commit_if_ok(|_| { // First, we instantiate each bound region in the supertype with a // fresh placeholder region. - let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(b); + let (b_prime, _) = self.infcx.replace_bound_vars_with_placeholders(&b); // Next, we instantiate each bound region in the subtype // with a fresh region variable. These region variables -- // but no other pre-existing region variables -- can name // the placeholders. let (a_prime, _) = - self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a); + self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, &a); debug!("a_prime={:?}", a_prime); debug!("b_prime={:?}", b_prime); // Compare types now that bound regions have been replaced. - let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; + let result = self.sub(a_is_expected).relate(a_prime, b_prime)?; debug!("higher_ranked_sub: OK result={:?}", result); diff --git a/src/librustc_infer/infer/lub.rs b/src/librustc_infer/infer/lub.rs index a0453db2cb499..3e2ea3d0f8fbf 100644 --- a/src/librustc_infer/infer/lub.rs +++ b/src/librustc_infer/infer/lub.rs @@ -43,8 +43,8 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { fn relate_with_variance>( &mut self, variance: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), @@ -85,8 +85,8 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, @@ -97,7 +97,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { // very challenging, switch to invariance. This is obviously // overly conservative but works ok in practice. self.relate_with_variance(ty::Variance::Invariant, a, b)?; - Ok(a.clone()) + Ok(a) } } @@ -118,8 +118,8 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { let mut sub = self.fields.sub(self.a_is_expected); - sub.relate(&a, &v)?; - sub.relate(&b, &v)?; + sub.relate(a, v)?; + sub.relate(b, v)?; Ok(()) } } diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index 2350c28dfaaff..59e08b85f26e8 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -159,6 +159,7 @@ where } } + // FIXME: consider taking `ty::Binder` directly, without the reference. fn create_scope( &mut self, value: &ty::Binder>, @@ -369,7 +370,7 @@ where universe, }; - generalizer.relate(&value, &value) + generalizer.relate(value, value) } } @@ -495,8 +496,8 @@ where fn relate_with_variance>( &mut self, variance: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { debug!("relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b); @@ -613,8 +614,8 @@ where fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, @@ -640,11 +641,10 @@ where debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance); - if !a.skip_binder().has_escaping_bound_vars() && !b.skip_binder().has_escaping_bound_vars() - { + if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { // Fast path for the common case. - self.relate(a.skip_binder(), b.skip_binder())?; - return Ok(a.clone()); + self.relate(a, b)?; + return Ok(ty::Binder::bind(a)); } if self.ambient_covariance() { @@ -654,8 +654,8 @@ where // instantiation of B (i.e., B instantiated with // universals). - let b_scope = self.create_scope(b, UniversallyQuantified(true)); - let a_scope = self.create_scope(a, UniversallyQuantified(false)); + let b_scope = self.create_scope(&b, UniversallyQuantified(true)); + let a_scope = self.create_scope(&a, UniversallyQuantified(false)); debug!("binders: a_scope = {:?} (existential)", a_scope); debug!("binders: b_scope = {:?} (universal)", b_scope); @@ -683,7 +683,7 @@ where // subtyping (i.e., `&'b u32 <: &{P} u32`). let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); - self.relate(a.skip_binder(), b.skip_binder())?; + self.relate(*a.skip_binder(), *b.skip_binder())?; self.ambient_variance = variance; @@ -698,8 +698,8 @@ where // instantiation of B (i.e., B instantiated with // existentials). Opposite of above. - let a_scope = self.create_scope(a, UniversallyQuantified(true)); - let b_scope = self.create_scope(b, UniversallyQuantified(false)); + let a_scope = self.create_scope(&a, UniversallyQuantified(true)); + let b_scope = self.create_scope(&b, UniversallyQuantified(false)); debug!("binders: a_scope = {:?} (universal)", a_scope); debug!("binders: b_scope = {:?} (existential)", b_scope); @@ -712,7 +712,7 @@ where let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); - self.relate(a.skip_binder(), b.skip_binder())?; + self.relate(*a.skip_binder(), *b.skip_binder())?; self.ambient_variance = variance; @@ -839,8 +839,8 @@ where fn relate_with_variance>( &mut self, variance: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { debug!( "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", @@ -890,7 +890,7 @@ where match variables.probe(vid) { TypeVariableValue::Known { value: u } => { drop(variables); - self.relate(&u, &u) + self.relate(u, u) } TypeVariableValue::Unknown { universe: _universe } => { if self.ambient_variance == ty::Bivariant { @@ -984,7 +984,7 @@ where let variable_table = &mut inner.const_unification_table(); let var_value = variable_table.probe_value(vid); match var_value.val.known() { - Some(u) => self.relate(&u, &u), + Some(u) => self.relate(u, u), None => { let new_var_id = variable_table.new_key(ConstVarValue { origin: var_value.origin, @@ -1001,8 +1001,8 @@ where fn binders( &mut self, - a: &ty::Binder, - _: &ty::Binder, + a: ty::Binder, + _: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, @@ -1010,7 +1010,7 @@ where debug!("TypeGeneralizer::binders(a={:?})", a); self.first_free_index.shift_in(1); - let result = self.relate(a.skip_binder(), a.skip_binder())?; + let result = self.relate(*a.skip_binder(), *a.skip_binder())?; self.first_free_index.shift_out(1); Ok(ty::Binder::bind(result)) } diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 90962d210b5b4..d190f7e434298 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -62,8 +62,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { fn relate_with_variance>( &mut self, variance: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), @@ -162,8 +162,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, diff --git a/src/librustc_middle/ty/_match.rs b/src/librustc_middle/ty/_match.rs index db9229ae3d214..55aafc0b42aa4 100644 --- a/src/librustc_middle/ty/_match.rs +++ b/src/librustc_middle/ty/_match.rs @@ -46,8 +46,8 @@ impl TypeRelation<'tcx> for Match<'tcx> { fn relate_with_variance>( &mut self, _: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { self.relate(a, b) } @@ -112,12 +112,12 @@ impl TypeRelation<'tcx> for Match<'tcx> { fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(ty::Binder::bind(self.relate(*a.skip_binder(), *b.skip_binder())?)) } } diff --git a/src/librustc_middle/ty/relate.rs b/src/librustc_middle/ty/relate.rs index e9a8b9095bf72..cee04ce8c6a83 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/src/librustc_middle/ty/relate.rs @@ -13,7 +13,6 @@ use rustc_hir::def_id::DefId; use rustc_span::DUMMY_SP; use rustc_target::spec::abi; use std::iter; -use std::rc::Rc; pub type RelateResult<'tcx, T> = Result>; @@ -42,7 +41,7 @@ pub trait TypeRelation<'tcx>: Sized { } /// Generic relation routine suitable for most anything. - fn relate>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> { + fn relate>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> { Relate::relate(self, a, b) } @@ -68,8 +67,8 @@ pub trait TypeRelation<'tcx>: Sized { fn relate_with_variance>( &mut self, variance: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T>; // Overridable relations. You shouldn't typically call these @@ -94,18 +93,18 @@ pub trait TypeRelation<'tcx>: Sized { fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>; } -pub trait Relate<'tcx>: TypeFoldable<'tcx> { +pub trait Relate<'tcx>: TypeFoldable<'tcx> + Copy { fn relate>( relation: &mut R, - a: &Self, - b: &Self, + a: Self, + b: Self, ) -> RelateResult<'tcx, Self>; } @@ -115,8 +114,8 @@ pub trait Relate<'tcx>: TypeFoldable<'tcx> { impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> { fn relate>( relation: &mut R, - a: &ty::TypeAndMut<'tcx>, - b: &ty::TypeAndMut<'tcx>, + a: ty::TypeAndMut<'tcx>, + b: ty::TypeAndMut<'tcx>, ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> { debug!("{}.mts({:?}, {:?})", relation.tag(), a, b); if a.mutbl != b.mutbl { @@ -127,7 +126,7 @@ impl<'tcx> Relate<'tcx> for ty::TypeAndMut<'tcx> { ast::Mutability::Not => ty::Covariant, ast::Mutability::Mut => ty::Invariant, }; - let ty = relation.relate_with_variance(variance, &a.ty, &b.ty)?; + let ty = relation.relate_with_variance(variance, a.ty, b.ty)?; Ok(ty::TypeAndMut { ty, mutbl }) } } @@ -143,7 +142,7 @@ pub fn relate_substs>( let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| { let variance = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(variance, &a, &b) + relation.relate_with_variance(variance, a, b) }); Ok(tcx.mk_substs(params)?) @@ -152,8 +151,8 @@ pub fn relate_substs>( impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { fn relate>( relation: &mut R, - a: &ty::FnSig<'tcx>, - b: &ty::FnSig<'tcx>, + a: ty::FnSig<'tcx>, + b: ty::FnSig<'tcx>, ) -> RelateResult<'tcx, ty::FnSig<'tcx>> { let tcx = relation.tcx(); @@ -164,8 +163,8 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { &b.c_variadic, ))); } - let unsafety = relation.relate(&a.unsafety, &b.unsafety)?; - let abi = relation.relate(&a.abi, &b.abi)?; + let unsafety = relation.relate(a.unsafety, b.unsafety)?; + let abi = relation.relate(a.abi, b.abi)?; if a.inputs().len() != b.inputs().len() { return Err(TypeError::ArgCount); @@ -180,9 +179,9 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { .chain(iter::once(((a.output(), b.output()), true))) .map(|((a, b), is_output)| { if is_output { - relation.relate(&a, &b) + relation.relate(a, b) } else { - relation.relate_with_variance(ty::Contravariant, &a, &b) + relation.relate_with_variance(ty::Contravariant, a, b) } }); Ok(ty::FnSig { @@ -197,13 +196,13 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { impl<'tcx> Relate<'tcx> for ast::Unsafety { fn relate>( relation: &mut R, - a: &ast::Unsafety, - b: &ast::Unsafety, + a: ast::Unsafety, + b: ast::Unsafety, ) -> RelateResult<'tcx, ast::Unsafety> { if a != b { - Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b))) + Err(TypeError::UnsafetyMismatch(expected_found(relation, &a, &b))) } else { - Ok(*a) + Ok(a) } } } @@ -211,18 +210,18 @@ impl<'tcx> Relate<'tcx> for ast::Unsafety { impl<'tcx> Relate<'tcx> for abi::Abi { fn relate>( relation: &mut R, - a: &abi::Abi, - b: &abi::Abi, + a: abi::Abi, + b: abi::Abi, ) -> RelateResult<'tcx, abi::Abi> { - if a == b { Ok(*a) } else { Err(TypeError::AbiMismatch(expected_found(relation, a, b))) } + if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(relation, &a, &b))) } } } impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> { fn relate>( relation: &mut R, - a: &ty::ProjectionTy<'tcx>, - b: &ty::ProjectionTy<'tcx>, + a: ty::ProjectionTy<'tcx>, + b: ty::ProjectionTy<'tcx>, ) -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> { if a.item_def_id != b.item_def_id { Err(TypeError::ProjectionMismatched(expected_found( @@ -231,7 +230,7 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> { &b.item_def_id, ))) } else { - let substs = relation.relate(&a.substs, &b.substs)?; + let substs = relation.relate(a.substs, b.substs)?; Ok(ty::ProjectionTy { item_def_id: a.item_def_id, substs: &substs }) } } @@ -240,8 +239,8 @@ impl<'tcx> Relate<'tcx> for ty::ProjectionTy<'tcx> { impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { fn relate>( relation: &mut R, - a: &ty::ExistentialProjection<'tcx>, - b: &ty::ExistentialProjection<'tcx>, + a: ty::ExistentialProjection<'tcx>, + b: ty::ExistentialProjection<'tcx>, ) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> { if a.item_def_id != b.item_def_id { Err(TypeError::ProjectionMismatched(expected_found( @@ -250,37 +249,18 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { &b.item_def_id, ))) } else { - let ty = relation.relate_with_variance(ty::Invariant, &a.ty, &b.ty)?; - let substs = relation.relate_with_variance(ty::Invariant, &a.substs, &b.substs)?; + let ty = relation.relate_with_variance(ty::Invariant, a.ty, b.ty)?; + let substs = relation.relate_with_variance(ty::Invariant, a.substs, b.substs)?; Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty }) } } } -impl<'tcx> Relate<'tcx> for Vec> { - fn relate>( - relation: &mut R, - a: &Vec>, - b: &Vec>, - ) -> RelateResult<'tcx, Vec>> { - // To be compatible, `a` and `b` must be for precisely the - // same set of traits and item names. We always require that - // projection bounds lists are sorted by trait-def-id and item-name, - // so we can just iterate through the lists pairwise, so long as they are the - // same length. - if a.len() != b.len() { - Err(TypeError::ProjectionBoundsLength(expected_found(relation, &a.len(), &b.len()))) - } else { - a.iter().zip(b).map(|(a, b)| relation.relate(a, b)).collect() - } - } -} - impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { fn relate>( relation: &mut R, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>, + a: ty::TraitRef<'tcx>, + b: ty::TraitRef<'tcx>, ) -> RelateResult<'tcx, ty::TraitRef<'tcx>> { // Different traits cannot be related. if a.def_id != b.def_id { @@ -295,8 +275,8 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { fn relate>( relation: &mut R, - a: &ty::ExistentialTraitRef<'tcx>, - b: &ty::ExistentialTraitRef<'tcx>, + a: ty::ExistentialTraitRef<'tcx>, + b: ty::ExistentialTraitRef<'tcx>, ) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> { // Different traits cannot be related. if a.def_id != b.def_id { @@ -308,18 +288,18 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { } } -#[derive(Debug, Clone, TypeFoldable)] +#[derive(Copy, Debug, Clone, TypeFoldable)] struct GeneratorWitness<'tcx>(&'tcx ty::List>); impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { fn relate>( relation: &mut R, - a: &GeneratorWitness<'tcx>, - b: &GeneratorWitness<'tcx>, + a: GeneratorWitness<'tcx>, + b: GeneratorWitness<'tcx>, ) -> RelateResult<'tcx, GeneratorWitness<'tcx>> { assert_eq!(a.0.len(), b.0.len()); let tcx = relation.tcx(); - let types = tcx.mk_type_list(a.0.iter().zip(b.0).map(|(a, b)| relation.relate(&a, &b)))?; + let types = tcx.mk_type_list(a.0.iter().zip(b.0).map(|(a, b)| relation.relate(a, b)))?; Ok(GeneratorWitness(types)) } } @@ -327,8 +307,8 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { impl<'tcx> Relate<'tcx> for Ty<'tcx> { fn relate>( relation: &mut R, - a: &Ty<'tcx>, - b: &Ty<'tcx>, + a: Ty<'tcx>, + b: Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> { relation.tys(a, b) } @@ -379,7 +359,7 @@ pub fn super_relate_tys>( (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)), - (&ty::Dynamic(ref a_obj, ref a_region), &ty::Dynamic(ref b_obj, ref b_region)) => { + (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { relation.relate_with_variance(ty::Contravariant, a_region, b_region) })?; @@ -392,7 +372,7 @@ pub fn super_relate_tys>( // All Generator types with the same id represent // the (anonymous) type of the same generator expression. So // all of their regions should be equated. - let substs = relation.relate(&a_substs, &b_substs)?; + let substs = relation.relate(a_substs, b_substs)?; Ok(tcx.mk_generator(a_id, substs, movability)) } @@ -402,7 +382,7 @@ pub fn super_relate_tys>( let a_types = a_types.map_bound(GeneratorWitness); let b_types = b_types.map_bound(GeneratorWitness); // Then remove the GeneratorWitness for the result - let types = relation.relate(&a_types, &b_types)?.map_bound(|witness| witness.0); + let types = relation.relate(a_types, b_types)?.map_bound(|witness| witness.0); Ok(tcx.mk_generator_witness(types)) } @@ -410,26 +390,26 @@ pub fn super_relate_tys>( // All Closure types with the same id represent // the (anonymous) type of the same closure expression. So // all of their regions should be equated. - let substs = relation.relate(&a_substs, &b_substs)?; + let substs = relation.relate(a_substs, b_substs)?; Ok(tcx.mk_closure(a_id, &substs)) } - (&ty::RawPtr(ref a_mt), &ty::RawPtr(ref b_mt)) => { + (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => { let mt = relation.relate(a_mt, b_mt)?; Ok(tcx.mk_ptr(mt)) } (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { - let r = relation.relate_with_variance(ty::Contravariant, &a_r, &b_r)?; + let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?; let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; - let mt = relation.relate(&a_mt, &b_mt)?; + let mt = relation.relate(a_mt, b_mt)?; Ok(tcx.mk_ref(r, mt)) } (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => { - let t = relation.relate(&a_t, &b_t)?; - match relation.relate(&sz_a, &sz_b) { + let t = relation.relate(a_t, b_t)?; + match relation.relate(sz_a, sz_b) { Ok(sz) => Ok(tcx.mk_ty(ty::Array(t, sz))), // FIXME(#72219) Implement improved diagnostics for mismatched array // length? @@ -450,16 +430,14 @@ pub fn super_relate_tys>( } (&ty::Slice(a_t), &ty::Slice(b_t)) => { - let t = relation.relate(&a_t, &b_t)?; + let t = relation.relate(a_t, b_t)?; Ok(tcx.mk_slice(t)) } (&ty::Tuple(as_), &ty::Tuple(bs)) => { if as_.len() == bs.len() { Ok(tcx.mk_tup( - as_.iter() - .zip(bs) - .map(|(a, b)| relation.relate(&a.expect_ty(), &b.expect_ty())), + as_.iter().zip(bs).map(|(a, b)| relation.relate(a.expect_ty(), b.expect_ty())), )?) } else if !(as_.is_empty() || bs.is_empty()) { Err(TypeError::TupleSize(expected_found(relation, &as_.len(), &bs.len()))) @@ -476,12 +454,12 @@ pub fn super_relate_tys>( } (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => { - let fty = relation.relate(&a_fty, &b_fty)?; + let fty = relation.relate(a_fty, b_fty)?; Ok(tcx.mk_fn_ptr(fty)) } // these two are already handled downstream in case of lazy normalization - (ty::Projection(a_data), ty::Projection(b_data)) => { + (&ty::Projection(a_data), &ty::Projection(b_data)) => { let projection_ty = relation.relate(a_data, b_data)?; Ok(tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs)) } @@ -603,8 +581,8 @@ pub fn super_relate_consts>( ty::ConstKind::Unevaluated(b_def_id, b_substs, b_promoted), ) if a_def_id == b_def_id && a_promoted == b_promoted => { let substs = - relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?; - Ok(ty::ConstKind::Unevaluated(a_def_id, &substs, a_promoted)) + relation.relate_with_variance(ty::Variance::Invariant, a_substs, b_substs)?; + Ok(ty::ConstKind::Unevaluated(a_def_id, substs, a_promoted)) } _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))), }; @@ -614,8 +592,8 @@ pub fn super_relate_consts>( impl<'tcx> Relate<'tcx> for &'tcx ty::List> { fn relate>( relation: &mut R, - a: &Self, - b: &Self, + a: Self, + b: Self, ) -> RelateResult<'tcx, Self> { let tcx = relation.tcx(); @@ -629,16 +607,16 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { b_v.sort_by(|a, b| a.stable_cmp(tcx, b)); b_v.dedup(); if a_v.len() != b_v.len() { - return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))); + return Err(TypeError::ExistentialMismatch(expected_found(relation, &a, &b))); } let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| { use crate::ty::ExistentialPredicate::*; match (ep_a, ep_b) { - (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)), - (Projection(ref a), Projection(ref b)) => Ok(Projection(relation.relate(a, b)?)), - (AutoTrait(ref a), AutoTrait(ref b)) if a == b => Ok(AutoTrait(*a)), - _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))), + (Trait(a), Trait(b)) => Ok(Trait(relation.relate(a, b)?)), + (Projection(a), Projection(b)) => Ok(Projection(relation.relate(a, b)?)), + (AutoTrait(a), AutoTrait(b)) if a == b => Ok(AutoTrait(a)), + _ => Err(TypeError::ExistentialMismatch(expected_found(relation, &a, &b))), } }); Ok(tcx.mk_existential_predicates(v)?) @@ -648,8 +626,8 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { fn relate>( relation: &mut R, - a: &ty::ClosureSubsts<'tcx>, - b: &ty::ClosureSubsts<'tcx>, + a: ty::ClosureSubsts<'tcx>, + b: ty::ClosureSubsts<'tcx>, ) -> RelateResult<'tcx, ty::ClosureSubsts<'tcx>> { let substs = relate_substs(relation, None, a.substs, b.substs)?; Ok(ty::ClosureSubsts { substs }) @@ -659,8 +637,8 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { impl<'tcx> Relate<'tcx> for ty::GeneratorSubsts<'tcx> { fn relate>( relation: &mut R, - a: &ty::GeneratorSubsts<'tcx>, - b: &ty::GeneratorSubsts<'tcx>, + a: ty::GeneratorSubsts<'tcx>, + b: ty::GeneratorSubsts<'tcx>, ) -> RelateResult<'tcx, ty::GeneratorSubsts<'tcx>> { let substs = relate_substs(relation, None, a.substs, b.substs)?; Ok(ty::GeneratorSubsts { substs }) @@ -670,8 +648,8 @@ impl<'tcx> Relate<'tcx> for ty::GeneratorSubsts<'tcx> { impl<'tcx> Relate<'tcx> for SubstsRef<'tcx> { fn relate>( relation: &mut R, - a: &SubstsRef<'tcx>, - b: &SubstsRef<'tcx>, + a: SubstsRef<'tcx>, + b: SubstsRef<'tcx>, ) -> RelateResult<'tcx, SubstsRef<'tcx>> { relate_substs(relation, None, a, b) } @@ -680,72 +658,48 @@ impl<'tcx> Relate<'tcx> for SubstsRef<'tcx> { impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { fn relate>( relation: &mut R, - a: &ty::Region<'tcx>, - b: &ty::Region<'tcx>, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - relation.regions(*a, *b) + relation.regions(a, b) } } impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> { fn relate>( relation: &mut R, - a: &&'tcx ty::Const<'tcx>, - b: &&'tcx ty::Const<'tcx>, + a: &'tcx ty::Const<'tcx>, + b: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - relation.consts(*a, *b) + relation.consts(a, b) } } impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder { fn relate>( relation: &mut R, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> { relation.binders(a, b) } } -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for Rc { - fn relate>( - relation: &mut R, - a: &Rc, - b: &Rc, - ) -> RelateResult<'tcx, Rc> { - let a: &T = a; - let b: &T = b; - Ok(Rc::new(relation.relate(a, b)?)) - } -} - -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for Box { - fn relate>( - relation: &mut R, - a: &Box, - b: &Box, - ) -> RelateResult<'tcx, Box> { - let a: &T = a; - let b: &T = b; - Ok(Box::new(relation.relate(a, b)?)) - } -} - impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { fn relate>( relation: &mut R, - a: &GenericArg<'tcx>, - b: &GenericArg<'tcx>, + a: GenericArg<'tcx>, + b: GenericArg<'tcx>, ) -> RelateResult<'tcx, GenericArg<'tcx>> { match (a.unpack(), b.unpack()) { (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => { - Ok(relation.relate(&a_lt, &b_lt)?.into()) + Ok(relation.relate(a_lt, b_lt)?.into()) } (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => { - Ok(relation.relate(&a_ty, &b_ty)?.into()) + Ok(relation.relate(a_ty, b_ty)?.into()) } (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => { - Ok(relation.relate(&a_ct, &b_ct)?.into()) + Ok(relation.relate(a_ct, b_ct)?.into()) } (GenericArgKind::Lifetime(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) @@ -763,22 +717,22 @@ impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { fn relate>( relation: &mut R, - a: &ty::TraitPredicate<'tcx>, - b: &ty::TraitPredicate<'tcx>, + a: ty::TraitPredicate<'tcx>, + b: ty::TraitPredicate<'tcx>, ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> { - Ok(ty::TraitPredicate { trait_ref: relation.relate(&a.trait_ref, &b.trait_ref)? }) + Ok(ty::TraitPredicate { trait_ref: relation.relate(a.trait_ref, b.trait_ref)? }) } } impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { fn relate>( relation: &mut R, - a: &ty::ProjectionPredicate<'tcx>, - b: &ty::ProjectionPredicate<'tcx>, + a: ty::ProjectionPredicate<'tcx>, + b: ty::ProjectionPredicate<'tcx>, ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> { Ok(ty::ProjectionPredicate { - projection_ty: relation.relate(&a.projection_ty, &b.projection_ty)?, - ty: relation.relate(&a.ty, &b.ty)?, + projection_ty: relation.relate(a.projection_ty, b.projection_ty)?, + ty: relation.relate(a.ty, b.ty)?, }) } } diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/type_check/relate_tys.rs index 285d9ed64691a..91b1a1fbd9705 100644 --- a/src/librustc_mir/borrow_check/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/type_check/relate_tys.rs @@ -31,7 +31,7 @@ pub(super) fn relate_types<'tcx>( NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), v, ) - .relate(&a, &b)?; + .relate(a, b)?; Ok(()) } diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index cff5efbfd0fd1..c41a27c6f431f 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -748,8 +748,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { && stack.iter().skip(1).any(|prev| { stack.obligation.param_env == prev.obligation.param_env && self.match_fresh_trait_refs( - &stack.fresh_trait_ref, - &prev.fresh_trait_ref, + stack.fresh_trait_ref, + prev.fresh_trait_ref, prev.obligation.param_env, ) }) @@ -1944,8 +1944,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn match_fresh_trait_refs( &self, - previous: &ty::PolyTraitRef<'tcx>, - current: &ty::PolyTraitRef<'tcx>, + previous: ty::PolyTraitRef<'tcx>, + current: ty::PolyTraitRef<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> bool { let mut matcher = ty::_match::Match::new(self.tcx(), param_env); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index b6cd8da236260..e6b3224050e9b 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -964,7 +964,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let sig = self .at(cause, self.param_env) .trace(prev_ty, new_ty) - .lub(&a_sig, &b_sig) + .lub(a_sig, b_sig) .map(|ok| self.register_infer_ok_obligations(ok))?; // Reify both sides and return the reified fn pointer type. diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index e27c2e4503910..f2696f27ffd53 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -227,10 +227,10 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let predicate_matches_closure = |p: Predicate<'tcx>| { let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); match (predicate.kind(), p.kind()) { - (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => { + (&ty::PredicateKind::Trait(a, _), &ty::PredicateKind::Trait(b, _)) => { relator.relate(a, b).is_ok() } - (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => { + (&ty::PredicateKind::Projection(a), &ty::PredicateKind::Projection(b)) => { relator.relate(a, b).is_ok() } _ => predicate == p, @@ -310,8 +310,8 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { fn relate_with_variance>( &mut self, _: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { // Here we ignore variance because we require drop impl's types // to be *exactly* the same as to the ones in the struct definition. @@ -354,8 +354,8 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, @@ -364,9 +364,9 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { // Anonymizing the LBRs is necessary to solve (Issue #59497). // After we do so, it should be totally fine to skip the binders. - let anon_a = self.tcx.anonymize_late_bound_regions(a); - let anon_b = self.tcx.anonymize_late_bound_regions(b); - self.relate(anon_a.skip_binder(), anon_b.skip_binder())?; + let anon_a = self.tcx.anonymize_late_bound_regions(&a); + let anon_b = self.tcx.anonymize_late_bound_regions(&b); + self.relate(*anon_a.skip_binder(), *anon_b.skip_binder())?; Ok(a.clone()) } From 71b45b97d30d0b0f2c006a21a99581fdf85df253 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 24 Jun 2020 23:40:33 +0200 Subject: [PATCH 52/92] change `skip_binder` to use T by value --- .../infer/canonical/query_response.rs | 4 ++-- src/librustc_infer/infer/combine.rs | 2 +- src/librustc_infer/infer/equate.rs | 2 +- src/librustc_infer/infer/nll_relate/mod.rs | 17 ++++++++--------- src/librustc_lint/builtin.rs | 2 +- src/librustc_middle/ich/impls_ty.rs | 2 +- src/librustc_middle/ty/_match.rs | 2 +- src/librustc_middle/ty/flags.rs | 12 ++++++------ src/librustc_middle/ty/fold.rs | 8 ++++---- src/librustc_middle/ty/layout.rs | 2 +- src/librustc_middle/ty/print/pretty.rs | 2 +- src/librustc_middle/ty/structural_impls.rs | 4 ++-- src/librustc_middle/ty/sty.rs | 16 ++++++---------- src/librustc_middle/ty/walk.rs | 2 +- .../borrow_check/diagnostics/conflict_errors.rs | 4 ++-- src/librustc_passes/intrinsicck.rs | 2 +- src/librustc_privacy/lib.rs | 10 +++++----- src/librustc_symbol_mangling/v0.rs | 2 +- src/librustc_trait_selection/opaque_types.rs | 2 +- .../traits/error_reporting/mod.rs | 2 +- .../traits/error_reporting/on_unimplemented.rs | 4 ++-- .../traits/error_reporting/suggestions.rs | 4 ++-- .../traits/select/candidate_assembly.rs | 8 ++++---- .../traits/select/confirmation.rs | 8 ++++---- src/librustc_trait_selection/traits/wf.rs | 2 +- src/librustc_traits/chalk/lowering.rs | 4 ++-- src/librustc_typeck/astconv.rs | 4 ++-- src/librustc_typeck/check/closure.rs | 4 ++-- src/librustc_typeck/check/compare_method.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/op.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 4 ++-- src/librustdoc/clean/mod.rs | 8 ++++---- 36 files changed, 78 insertions(+), 83 deletions(-) diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/src/librustc_infer/infer/canonical/query_response.rs index a6d7b403fe7a9..5cba581b9dffb 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/src/librustc_infer/infer/canonical/query_response.rs @@ -302,7 +302,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // Screen out `'a: 'a` cases -- we skip the binder here but // only compare the inner values to one another, so they are still at // consistent binding levels. - let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); + let ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); if k1 != r2.into() { Some(r_c) } else { None } }), ); @@ -526,7 +526,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) -> impl Iterator> + 'a + Captures<'tcx> { unsubstituted_region_constraints.iter().map(move |constraint| { let constraint = substitute_value(self.tcx, result_subst, constraint); - let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below + let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below Obligation::new( cause.clone(), diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index fa54d815055ec..c8d4e9f0e14b9 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -496,7 +496,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(*a.skip_binder(), *b.skip_binder())?)) + Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) } fn relate_item_substs( diff --git a/src/librustc_infer/infer/equate.rs b/src/librustc_infer/infer/equate.rs index 6826956b38bd8..7de752d1de0db 100644 --- a/src/librustc_infer/infer/equate.rs +++ b/src/librustc_infer/infer/equate.rs @@ -135,7 +135,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { self.fields.higher_ranked_sub(b, a, self.a_is_expected) } else { // Fast path for the common case. - self.relate(*a.skip_binder(), *b.skip_binder())?; + self.relate(a.skip_binder(), b.skip_binder())?; Ok(a) } } diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index 59e08b85f26e8..cb1f1c08d88f8 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -159,10 +159,9 @@ where } } - // FIXME: consider taking `ty::Binder` directly, without the reference. fn create_scope( &mut self, - value: &ty::Binder>, + value: ty::Binder>, universally_quantified: UniversallyQuantified, ) -> BoundRegionScope<'tcx> { let mut scope = BoundRegionScope::default(); @@ -654,8 +653,8 @@ where // instantiation of B (i.e., B instantiated with // universals). - let b_scope = self.create_scope(&b, UniversallyQuantified(true)); - let a_scope = self.create_scope(&a, UniversallyQuantified(false)); + let b_scope = self.create_scope(b, UniversallyQuantified(true)); + let a_scope = self.create_scope(a, UniversallyQuantified(false)); debug!("binders: a_scope = {:?} (existential)", a_scope); debug!("binders: b_scope = {:?} (universal)", b_scope); @@ -683,7 +682,7 @@ where // subtyping (i.e., `&'b u32 <: &{P} u32`). let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); - self.relate(*a.skip_binder(), *b.skip_binder())?; + self.relate(a.skip_binder(), b.skip_binder())?; self.ambient_variance = variance; @@ -698,8 +697,8 @@ where // instantiation of B (i.e., B instantiated with // existentials). Opposite of above. - let a_scope = self.create_scope(&a, UniversallyQuantified(true)); - let b_scope = self.create_scope(&b, UniversallyQuantified(false)); + let a_scope = self.create_scope(a, UniversallyQuantified(true)); + let b_scope = self.create_scope(b, UniversallyQuantified(false)); debug!("binders: a_scope = {:?} (universal)", a_scope); debug!("binders: b_scope = {:?} (existential)", b_scope); @@ -712,7 +711,7 @@ where let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); - self.relate(*a.skip_binder(), *b.skip_binder())?; + self.relate(a.skip_binder(), b.skip_binder())?; self.ambient_variance = variance; @@ -1010,7 +1009,7 @@ where debug!("TypeGeneralizer::binders(a={:?})", a); self.first_free_index.shift_in(1); - let result = self.relate(*a.skip_binder(), *a.skip_binder())?; + let result = self.relate(a.skip_binder(), a.skip_binder())?; self.first_free_index.shift_out(1); Ok(ty::Binder::bind(result)) } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 36d2954ac6ef7..d55cbbe19c279 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -911,7 +911,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { } let sig = cx.tables().node_type(expr.hir_id).fn_sig(cx.tcx); let from = sig.inputs().skip_binder()[0]; - let to = *sig.output().skip_binder(); + let to = sig.output().skip_binder(); return Some((from, to)); } None diff --git a/src/librustc_middle/ich/impls_ty.rs b/src/librustc_middle/ich/impls_ty.rs index ef6247881c0be..8f15c99f951fe 100644 --- a/src/librustc_middle/ich/impls_ty.rs +++ b/src/librustc_middle/ich/impls_ty.rs @@ -123,7 +123,7 @@ where T: HashStable>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - self.skip_binder().hash_stable(hcx, hasher); + self.as_ref().skip_binder().hash_stable(hcx, hasher); } } diff --git a/src/librustc_middle/ty/_match.rs b/src/librustc_middle/ty/_match.rs index 55aafc0b42aa4..4693a2f66fb4c 100644 --- a/src/librustc_middle/ty/_match.rs +++ b/src/librustc_middle/ty/_match.rs @@ -118,6 +118,6 @@ impl TypeRelation<'tcx> for Match<'tcx> { where T: Relate<'tcx>, { - Ok(ty::Binder::bind(self.relate(*a.skip_binder(), *b.skip_binder())?)) + Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) } } diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index c782eee938721..0e86fcf53b247 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -88,13 +88,13 @@ impl FlagComputation { self.add_substs(substs); } - &ty::GeneratorWitness(ref ts) => { + &ty::GeneratorWitness(ts) => { let mut computation = FlagComputation::new(); - computation.add_tys(&ts.skip_binder()[..]); + computation.add_tys(ts.skip_binder()); self.add_bound_computation(computation); } - &ty::Closure(_, ref substs) => { + &ty::Closure(_, substs) => { self.add_substs(substs); } @@ -122,7 +122,7 @@ impl FlagComputation { self.add_substs(substs); } - &ty::Projection(ref data) => { + &ty::Projection(data) => { self.add_flags(TypeFlags::HAS_TY_PROJECTION); self.add_projection_ty(data); } @@ -211,7 +211,7 @@ impl FlagComputation { self.add_bound_computation(computation); } - ty::PredicateKind::Projection(projection) => { + &ty::PredicateKind::Projection(projection) => { let mut computation = FlagComputation::new(); let ty::ProjectionPredicate { projection_ty, ty } = projection.skip_binder(); computation.add_projection_ty(projection_ty); @@ -298,7 +298,7 @@ impl FlagComputation { self.add_ty(projection.ty); } - fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy<'_>) { + fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) { self.add_substs(projection_ty.substs); } diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index 2d25c7c6ac983..492f8ce9ef1a9 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -336,7 +336,7 @@ impl<'tcx> TyCtxt<'tcx> { { fn visit_binder>(&mut self, t: &Binder) -> bool { self.outer_index.shift_in(1); - let result = t.skip_binder().visit_with(self); + let result = t.as_ref().skip_binder().visit_with(self); self.outer_index.shift_out(1); result } @@ -558,7 +558,7 @@ impl<'tcx> TyCtxt<'tcx> { let fld_c = |bound_ct, ty| { self.mk_const(ty::Const { val: ty::ConstKind::Bound(ty::INNERMOST, bound_ct), ty }) }; - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) + self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c) } /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping @@ -617,7 +617,7 @@ impl<'tcx> TyCtxt<'tcx> { H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>, T: TypeFoldable<'tcx>, { - self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t, fld_c) + self.replace_escaping_bound_vars(value.as_ref().skip_binder(), fld_r, fld_t, fld_c) } /// Replaces any late-bound regions bound in `value` with @@ -673,7 +673,7 @@ impl<'tcx> TyCtxt<'tcx> { T: TypeFoldable<'tcx>, { let mut collector = LateBoundRegionsCollector::new(just_constraint); - let result = value.skip_binder().visit_with(&mut collector); + let result = value.as_ref().skip_binder().visit_with(&mut collector); assert!(!result); // should never have stopped early collector.regions } diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index e4cc96dd83bfb..39b8566e7a873 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -2303,7 +2303,7 @@ impl<'tcx> ty::Instance<'tcx> { let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); sig.map_bound(|sig| tcx.mk_fn_sig( - iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), + iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), sig.output(), sig.c_variadic, sig.unsafety, diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 061214249713d..9fa1260f64d74 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -189,7 +189,7 @@ pub trait PrettyPrinter<'tcx>: where T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, { - value.skip_binder().print(self) + value.as_ref().skip_binder().print(self) } /// Prints comma-separated elements. diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index f736037b5c15a..d0d972727bcd8 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -514,7 +514,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder { type Lifted = ty::Binder; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(self.skip_binder()).map(ty::Binder::bind) + tcx.lift(self.as_ref().skip_binder()).map(ty::Binder::bind) } } @@ -798,7 +798,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.skip_binder().visit_with(visitor) + self.as_ref().skip_binder().visit_with(visitor) } fn visit_with>(&self, visitor: &mut V) -> bool { diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 8f86d2ef522d3..c7683cefd82f6 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -615,7 +615,7 @@ impl<'tcx> ExistentialPredicate<'tcx> { impl<'tcx> Binder> { pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; - match *self.skip_binder() { + match self.skip_binder() { ExistentialPredicate::Trait(tr) => { Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx) } @@ -776,7 +776,7 @@ impl<'tcx> PolyTraitRef<'tcx> { pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { // Note that we preserve binding levels - Binder(ty::TraitPredicate { trait_ref: *self.skip_binder() }) + Binder(ty::TraitPredicate { trait_ref: self.skip_binder() }) } } @@ -880,8 +880,8 @@ impl Binder { /// - extracting the `DefId` from a PolyTraitRef; /// - comparing the self type of a PolyTraitRef to see if it is equal to /// a type parameter `X`, since the type `X` does not reference any regions - pub fn skip_binder(&self) -> &T { - &self.0 + pub fn skip_binder(self) -> T { + self.0 } pub fn as_ref(&self) -> Binder<&T> { @@ -916,11 +916,7 @@ impl Binder { where T: TypeFoldable<'tcx>, { - if self.skip_binder().has_escaping_bound_vars() { - None - } else { - Some(self.skip_binder().clone()) - } + if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } } /// Given two things that have the same binder level, @@ -997,7 +993,7 @@ impl<'tcx> ProjectionTy<'tcx> { } } -#[derive(Clone, Debug, TypeFoldable)] +#[derive(Copy, Clone, Debug, TypeFoldable)] pub struct GenSig<'tcx> { pub resume_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, diff --git a/src/librustc_middle/ty/walk.rs b/src/librustc_middle/ty/walk.rs index 633d4fda8a46d..82c649b8f543b 100644 --- a/src/librustc_middle/ty/walk.rs +++ b/src/librustc_middle/ty/walk.rs @@ -133,7 +133,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) ty::Dynamic(obj, lt) => { stack.push(lt.into()); stack.extend(obj.iter().rev().flat_map(|predicate| { - let (substs, opt_ty) = match *predicate.skip_binder() { + let (substs, opt_ty) = match predicate.skip_binder() { ty::ExistentialPredicate::Trait(tr) => (tr.substs, None), ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)), ty::ExistentialPredicate::AutoTrait(_) => diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index e85f69554d0c8..17846055f6c96 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -1923,7 +1923,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // We use a mix of the HIR and the Ty types to get information // as the HIR doesn't have full types for closure arguments. - let return_ty = *sig.output().skip_binder(); + let return_ty = sig.output().skip_binder(); let mut return_span = fn_decl.output.span(); if let hir::FnRetTy::Return(ty) = &fn_decl.output { if let hir::TyKind::Rptr(lifetime, _) = ty.kind { @@ -1965,7 +1965,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let argument_ty = sig.inputs().skip_binder().first()?; let return_span = fn_decl.output.span(); - let return_ty = *sig.output().skip_binder(); + let return_ty = sig.output().skip_binder(); // We expect the first argument to be a reference. match argument_ty.kind { diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs index 683039df15ac6..e4f4885690fd9 100644 --- a/src/librustc_passes/intrinsicck.rs +++ b/src/librustc_passes/intrinsicck.rs @@ -422,7 +422,7 @@ impl Visitor<'tcx> for ExprVisitor<'tcx> { let typ = self.tables.node_type(expr.hir_id); let sig = typ.fn_sig(self.tcx); let from = sig.inputs().skip_binder()[0]; - let to = *sig.output().skip_binder(); + let to = sig.output().skip_binder(); self.check_transmute(expr.span, from, to); } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 9e6e7ea962bc3..20f09ef52f00b 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -92,14 +92,14 @@ where for (predicate, _span) in predicates { match predicate.kind() { ty::PredicateKind::Trait(poly_predicate, _) => { - let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder(); + let ty::TraitPredicate { trait_ref } = poly_predicate.skip_binder(); if self.visit_trait(trait_ref) { return true; } } ty::PredicateKind::Projection(poly_predicate) => { let ty::ProjectionPredicate { projection_ty, ty } = - *poly_predicate.skip_binder(); + poly_predicate.skip_binder(); if ty.visit_with(self) { return true; } @@ -108,7 +108,7 @@ where } } ty::PredicateKind::TypeOutlives(poly_predicate) => { - let ty::OutlivesPredicate(ty, _region) = *poly_predicate.skip_binder(); + let ty::OutlivesPredicate(ty, _region) = poly_predicate.skip_binder(); if ty.visit_with(self) { return true; } @@ -175,7 +175,7 @@ where ty::Dynamic(predicates, ..) => { // All traits in the list are considered the "primary" part of the type // and are visited by shallow visitors. - for predicate in *predicates.skip_binder() { + for predicate in predicates.skip_binder() { let trait_ref = match predicate { ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), @@ -1270,7 +1270,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { ); for (trait_predicate, _, _) in bounds.trait_bounds { - if self.visit_trait(*trait_predicate.skip_binder()) { + if self.visit_trait(trait_predicate.skip_binder()) { return; } } diff --git a/src/librustc_symbol_mangling/v0.rs b/src/librustc_symbol_mangling/v0.rs index 7d117b77cf5e5..ecf27fbf54220 100644 --- a/src/librustc_symbol_mangling/v0.rs +++ b/src/librustc_symbol_mangling/v0.rs @@ -219,7 +219,7 @@ impl SymbolMangler<'tcx> { lifetime_depths.end += lifetimes; self.binders.push(BinderLevel { lifetime_depths }); - self = print_value(self, value.skip_binder())?; + self = print_value(self, value.as_ref().skip_binder())?; self.binders.pop(); Ok(self) diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index adccdd0b2617a..ce478de7c755c 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -691,7 +691,7 @@ where OP: FnMut(ty::Region<'tcx>), { fn visit_binder>(&mut self, t: &ty::Binder) -> bool { - t.skip_binder().visit_with(self); + t.as_ref().skip_binder().visit_with(self); false // keep visiting } diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index fd0c1a54d27ad..49e43873df759 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -1569,7 +1569,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // no need to overload user in such cases return; } - let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); + let SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); self.need_type_info_err(body_id, span, a, ErrorCode::E0282) diff --git a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs b/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs index fd87759a7621f..ec51dddc2c810 100644 --- a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs @@ -122,7 +122,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> OnUnimplementedNote { let def_id = self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id()); - let trait_ref = *trait_ref.skip_binder(); + let trait_ref = trait_ref.skip_binder(); let mut flags = vec![]; flags.push(( @@ -219,7 +219,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } if let ty::Dynamic(traits, _) = self_ty.kind { - for t in *traits.skip_binder() { + for t in traits.skip_binder() { if let ty::ExistentialPredicate::Trait(trait_ref) = t { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) } diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 176bd90303ddd..1fafa9ec035ce 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -1179,7 +1179,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ) -> DiagnosticBuilder<'tcx> { crate fn build_fn_sig_string<'tcx>( tcx: TyCtxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, ) -> String { let inputs = trait_ref.substs.type_at(1); let sig = if let ty::Tuple(inputs) = inputs.kind { @@ -1360,7 +1360,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } ty::GeneratorWitness(..) => {} _ if generator.is_none() => { - trait_ref = Some(*derived_obligation.parent_trait_ref.skip_binder()); + trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder()); target_ty = Some(ty); } _ => {} diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/src/librustc_trait_selection/traits/select/candidate_assembly.rs index 4dab5814f7b7e..91c162872b215 100644 --- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs +++ b/src/librustc_trait_selection/traits/select/candidate_assembly.rs @@ -220,7 +220,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters. - let self_ty = *obligation.self_ty().skip_binder(); + let self_ty = obligation.self_ty().skip_binder(); match self_ty.kind { ty::Generator(..) => { debug!( @@ -299,7 +299,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // Okay to skip binder because what we are inspecting doesn't involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); + let self_ty = obligation.self_ty().skip_binder(); match self_ty.kind { ty::Infer(ty::TyVar(_)) => { debug!("assemble_fn_pointer_candidates: ambiguous self-type"); @@ -362,7 +362,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { // Okay to skip binder here because the tests we do below do not involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); + let self_ty = obligation.self_ty().skip_binder(); debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); let def_id = obligation.predicate.def_id(); @@ -583,7 +583,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { // Okay to skip binder here because the tests we do below do not involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); + let self_ty = obligation.self_ty().skip_binder(); debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); let def_id = obligation.predicate.def_id(); diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/src/librustc_trait_selection/traits/select/confirmation.rs index 834bf17227d2e..fa970589bbbf6 100644 --- a/src/librustc_trait_selection/traits/select/confirmation.rs +++ b/src/librustc_trait_selection/traits/select/confirmation.rs @@ -326,7 +326,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // probably flatten the binder from the obligation and the binder // from the object. Have to try to make a broken test case that // results. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); let poly_trait_ref = match self_ty.kind { ty::Dynamic(ref data, ..) => data .principal() @@ -379,7 +379,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("confirm_fn_pointer_candidate({:?})", obligation); // Okay to skip binder; it is reintroduced below. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); let sig = self_ty.fn_sig(self.tcx()); let trait_ref = closure_trait_ref_and_return_type( self.tcx(), @@ -448,7 +448,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); let (generator_def_id, substs) = match self_ty.kind { ty::Generator(id, substs, _) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), @@ -497,7 +497,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope // type/region parameters. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); let (closure_def_id, substs) = match self_ty.kind { ty::Closure(id, substs) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 1825c159ff3fb..ebff2dd9b23c1 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -695,7 +695,7 @@ pub fn object_region_bounds<'tcx>( let open_ty = tcx.mk_ty_infer(ty::FreshTy(0)); let predicates = existential_predicates.iter().filter_map(|predicate| { - if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() { + if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() { None } else { Some(predicate.with_self_ty(tcx, open_ty)) diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index e09359b8b3fc1..ed021e5b9de1b 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -615,7 +615,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( ty: &'a Binder, ) -> (T, chalk_ir::VariableKinds>, BTreeMap) { let mut bound_vars_collector = BoundVarsCollector::new(); - ty.skip_binder().visit_with(&mut bound_vars_collector); + ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector); let mut parameters = bound_vars_collector.parameters; let named_parameters: BTreeMap = bound_vars_collector .named_parameters @@ -625,7 +625,7 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( .collect(); let mut bound_var_substitutor = NamedBoundVarSubstitutor::new(tcx, &named_parameters); - let new_ty = ty.skip_binder().fold_with(&mut bound_var_substitutor); + let new_ty = ty.as_ref().skip_binder().fold_with(&mut bound_var_substitutor); for var in named_parameters.values() { parameters.insert(*var, chalk_ir::VariableKind::Lifetime); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1b08bf2fc7710..5d1949626dd84 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1802,7 +1802,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Calling `skip_binder` is okay because the predicates are re-bound. let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| ty::ExistentialPredicate::Trait(*trait_ref.skip_binder())); + .map(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref.skip_binder())); let auto_trait_predicates = auto_traits .into_iter() .map(|trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())); @@ -1810,7 +1810,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .chain(auto_trait_predicates) .chain( existential_projections - .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())), + .map(|x| ty::ExistentialPredicate::Projection(x.skip_binder())), ) .collect::>(); v.sort_by(|a, b| a.stable_cmp(tcx, b)); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 6d09ddc925ffe..fce2b18b782fb 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -188,7 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), ty::FnPtr(sig) => { - let expected_sig = ExpectedSig { cause_span: None, sig: *sig.skip_binder() }; + let expected_sig = ExpectedSig { cause_span: None, sig: sig.skip_binder() }; (Some(expected_sig), Some(ty::ClosureKind::Fn)) } _ => (None, None), @@ -501,7 +501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ((hir_ty, &supplied_ty), expected_ty) in decl .inputs .iter() - .zip(*supplied_sig.inputs().skip_binder()) // binder moved to (*) below + .zip(supplied_sig.inputs().skip_binder()) // binder moved to (*) below .zip(expected_sigs.liberated_sig.inputs()) // `liberated_sig` is E'. { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 4e97ba41dcbb3..e6217e0cc1b6e 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -502,7 +502,7 @@ fn compare_self_type<'tcx>( ty::ImplContainer(_) => impl_trait_ref.self_ty(), ty::TraitContainer(_) => tcx.types.self_param, }; - let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder(); + let self_arg_ty = tcx.fn_sig(method.def_id).input(0).skip_binder(); let param_env = ty::ParamEnv::reveal_all(); tcx.infer_ctxt().enter(|infcx| { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index f2696f27ffd53..f6991120f3479 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -366,7 +366,7 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { // After we do so, it should be totally fine to skip the binders. let anon_a = self.tcx.anonymize_late_bound_regions(&a); let anon_b = self.tcx.anonymize_late_bound_regions(&b); - self.relate(*anon_a.skip_binder(), *anon_b.skip_binder())?; + self.relate(anon_a.skip_binder(), anon_b.skip_binder())?; Ok(a.clone()) } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 67bdd04d3715c..b75dac52b93e5 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -608,7 +608,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), // Point at the trait object that couldn't satisfy the bound. ty::Dynamic(preds, _) => { - for pred in *preds.skip_binder() { + for pred in preds.skip_binder() { match pred { ty::ExistentialPredicate::Trait(tr) => { bound_spans.push((def_span(tr.def_id), msg.clone())) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7c4048ab22302..b617937d6bd54 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2446,7 +2446,7 @@ fn bounds_from_generic_predicates( /// Return placeholder code for the given function. fn fn_sig_suggestion( tcx: TyCtxt<'_>, - sig: &ty::FnSig<'_>, + sig: ty::FnSig<'_>, ident: Ident, predicates: ty::GenericPredicates<'_>, assoc: &ty::AssocItem, diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 94a5685a992fe..a1e060b97ad28 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -500,7 +500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } // We're emitting a suggestion, so we can just ignore regions - let fn_sig = *self.tcx.fn_sig(def_id).skip_binder(); + let fn_sig = self.tcx.fn_sig(def_id).skip_binder(); let other_ty = if let FnDef(def_id, _) = other_ty.kind { if !self.tcx.has_typeck_tables(def_id) { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a45a44a6801e8..3b203dd222afb 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -216,7 +216,7 @@ fn check_object_overlap<'tcx>( let component_def_ids = data.iter().flat_map(|predicate| { match predicate.skip_binder() { ty::ExistentialPredicate::Trait(tr) => Some(tr.def_id), - ty::ExistentialPredicate::AutoTrait(def_id) => Some(*def_id), + ty::ExistentialPredicate::AutoTrait(def_id) => Some(def_id), // An associated type projection necessarily comes with // an additional `Trait` requirement. ty::ExistentialPredicate::Projection(..) => None, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b486e3d3536c9..8920203e6af40 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2102,11 +2102,11 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( .emit(); } }; - for (input, ty) in decl.inputs.iter().zip(*fty.inputs().skip_binder()) { + for (input, ty) in decl.inputs.iter().zip(fty.inputs().skip_binder()) { check(&input, ty) } if let hir::FnRetTy::Return(ref ty) = decl.output { - check(&ty, *fty.output().skip_binder()) + check(&ty, fty.output().skip_binder()) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 73fe87b05d477..bfe8464347d29 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -347,7 +347,7 @@ impl Clean for (ty::PolyTraitRef<'_>, &[TypeBinding]) { GenericBound::TraitBound( PolyTrait { - trait_: (*poly_trait_ref.skip_binder(), bounds).clean(cx), + trait_: (poly_trait_ref.skip_binder(), bounds).clean(cx), generic_params: late_bound_regions, }, hir::TraitBoundModifier::None, @@ -549,7 +549,7 @@ impl<'tcx> Clean> for ty::PolyOutlivesPredicate, impl<'tcx> Clean for ty::PolyProjectionPredicate<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> WherePredicate { - let ty::ProjectionPredicate { projection_ty, ty } = *self.skip_binder(); + let ty::ProjectionPredicate { projection_ty, ty } = self.skip_binder(); WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) } } } @@ -1177,7 +1177,7 @@ impl Clean for ty::AssocItem { ty::ImplContainer(def_id) => cx.tcx.type_of(def_id), ty::TraitContainer(_) => cx.tcx.types.self_param, }; - let self_arg_ty = *sig.input(0).skip_binder(); + let self_arg_ty = sig.input(0).skip_binder(); if self_arg_ty == self_ty { decl.inputs.values[0].type_ = Generic(String::from("Self")); } else if let ty::Ref(_, ty, _) = self_arg_ty.kind { @@ -1679,7 +1679,7 @@ impl<'tcx> Clean for Ty<'tcx> { if let ty::PredicateKind::Projection(proj) = pred.kind() { let proj = proj.skip_binder(); if proj.projection_ty.trait_ref(cx.tcx) - == *trait_ref.skip_binder() + == trait_ref.skip_binder() { Some(TypeBinding { name: cx From f632bd1a5052b647932de7be6975b1baf15141e9 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Wed, 24 Jun 2020 23:48:41 +0200 Subject: [PATCH 53/92] remove unused `TypeError::ProjectionBoundsLength` --- src/librustc_middle/ty/error.rs | 9 --------- src/librustc_middle/ty/structural_impls.rs | 1 - 2 files changed, 10 deletions(-) diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs index 6113359ca93a7..30ff5a2d9ebdf 100644 --- a/src/librustc_middle/ty/error.rs +++ b/src/librustc_middle/ty/error.rs @@ -57,7 +57,6 @@ pub enum TypeError<'tcx> { /// type). CyclicTy(Ty<'tcx>), ProjectionMismatched(ExpectedFound), - ProjectionBoundsLength(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ObjectUnsafeCoercion(DefId), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), @@ -174,13 +173,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { tcx.def_path_str(values.found) ) }), - ProjectionBoundsLength(ref values) => write!( - f, - "expected {} associated type binding{}, found {}", - values.expected, - pluralize!(values.expected), - values.found - ), ExistentialMismatch(ref values) => report_maybe_different( f, &format!("trait `{}`", values.expected), @@ -216,7 +208,6 @@ impl<'tcx> TypeError<'tcx> { | RegionsPlaceholderMismatch | Traits(_) | ProjectionMismatched(_) - | ProjectionBoundsLength(_) | ExistentialMismatch(_) | ConstMismatch(_) | IntrinsicCast diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index d0d972727bcd8..1d3607fe32ffc 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -655,7 +655,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { VariadicMismatch(x) => VariadicMismatch(x), CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)), ProjectionMismatched(x) => ProjectionMismatched(x), - ProjectionBoundsLength(x) => ProjectionBoundsLength(x), Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch), From 69e49908f9a3fa2ebee94f67825bce15118c10ba Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 30 Jun 2020 09:20:08 +0200 Subject: [PATCH 54/92] update `equal_up_to_regions` --- src/librustc_mir/transform/validate.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index d3f486c815e6c..e794a6949d2f0 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -74,8 +74,8 @@ pub fn equal_up_to_regions( fn relate_with_variance>( &mut self, _: ty::Variance, - a: &T, - b: &T, + a: T, + b: T, ) -> RelateResult<'tcx, T> { // Ignore variance, require types to be exactly the same. self.relate(a, b) @@ -108,8 +108,8 @@ pub fn equal_up_to_regions( fn binders( &mut self, - a: &ty::Binder, - b: &ty::Binder, + a: ty::Binder, + b: ty::Binder, ) -> RelateResult<'tcx, ty::Binder> where T: Relate<'tcx>, @@ -121,7 +121,7 @@ pub fn equal_up_to_regions( // Instantiate and run relation. let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env }; - relator.relate(&src, &dest).is_ok() + relator.relate(src, dest).is_ok() } struct TypeChecker<'a, 'tcx> { From f3645ca6ca39bd891af3f0bd82b81f9a13718f6c Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Tue, 30 Jun 2020 10:56:10 +0200 Subject: [PATCH 55/92] remove rustdoc warnings --- src/librustc_mir_build/hair/pattern/_match.rs | 197 +++++++++--------- 1 file changed, 99 insertions(+), 98 deletions(-) diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index 6ac5d41ec6135..18b92bf29bf1b 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -4,8 +4,8 @@ //! This file includes the logic for exhaustiveness and usefulness checking for //! pattern-matching. Specifically, given a list of patterns for a type, we can //! tell whether: -//! (a) the patterns cover every possible constructor for the type [exhaustiveness] -//! (b) each pattern is necessary [usefulness] +//! (a) the patterns cover every possible constructor for the type (exhaustiveness) +//! (b) each pattern is necessary (usefulness) //! //! The algorithm implemented here is a modified version of the one described in: //! http://moscova.inria.fr/~maranget/papers/warn/index.html @@ -101,53 +101,54 @@ //! To match the paper, the top of the stack is at the beginning / on the left. //! //! There are two important operations on pattern-stacks necessary to understand the algorithm: -//! 1. We can pop a given constructor off the top of a stack. This operation is called -//! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or -//! `None`) and `p` a pattern-stack. -//! If the pattern on top of the stack can cover `c`, this removes the constructor and -//! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. -//! Otherwise the pattern-stack is discarded. -//! This essentially filters those pattern-stacks whose top covers the constructor `c` and -//! discards the others. //! -//! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we -//! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the -//! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get -//! nothing back. +//! 1. We can pop a given constructor off the top of a stack. This operation is called +//! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or +//! `None`) and `p` a pattern-stack. +//! If the pattern on top of the stack can cover `c`, this removes the constructor and +//! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. +//! Otherwise the pattern-stack is discarded. +//! This essentially filters those pattern-stacks whose top covers the constructor `c` and +//! discards the others. //! -//! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` -//! on top of the stack, and we have four cases: -//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We -//! push onto the stack the arguments of this constructor, and return the result: -//! r_1, .., r_a, p_2, .., p_n -//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and -//! return nothing. -//! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has -//! arguments (its arity), and return the resulting stack: -//! _, .., _, p_2, .., p_n -//! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting -//! stack: -//! S(c, (r_1, p_2, .., p_n)) -//! S(c, (r_2, p_2, .., p_n)) +//! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we +//! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the +//! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get +//! nothing back. //! -//! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is -//! a pattern-stack. -//! This is used when we know there are missing constructor cases, but there might be -//! existing wildcard patterns, so to check the usefulness of the matrix, we have to check -//! all its *other* components. +//! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` +//! on top of the stack, and we have four cases: +//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We +//! push onto the stack the arguments of this constructor, and return the result: +//! r_1, .., r_a, p_2, .., p_n +//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and +//! return nothing. +//! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has +//! arguments (its arity), and return the resulting stack: +//! _, .., _, p_2, .., p_n +//! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting +//! stack: +//! S(c, (r_1, p_2, .., p_n)) +//! S(c, (r_2, p_2, .., p_n)) //! -//! It is computed as follows. We look at the pattern `p_1` on top of the stack, -//! and we have three cases: -//! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. -//! 1.2. `p_1 = _`. We return the rest of the stack: -//! p_2, .., p_n -//! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting -//! stack. -//! D((r_1, p_2, .., p_n)) -//! D((r_2, p_2, .., p_n)) +//! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is +//! a pattern-stack. +//! This is used when we know there are missing constructor cases, but there might be +//! existing wildcard patterns, so to check the usefulness of the matrix, we have to check +//! all its *other* components. //! -//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the -//! exhaustive integer matching rules, so they're written here for posterity. +//! It is computed as follows. We look at the pattern `p_1` on top of the stack, +//! and we have three cases: +//! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. +//! 1.2. `p_1 = _`. We return the rest of the stack: +//! p_2, .., p_n +//! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting +//! stack. +//! D((r_1, p_2, .., p_n)) +//! D((r_2, p_2, .., p_n)) +//! +//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the +//! exhaustive integer matching rules, so they're written here for posterity. //! //! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by //! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with @@ -168,66 +169,66 @@ //! //! Inductive step. (`n > 0`, i.e., whether there's at least one column //! [which may then be expanded into further columns later]) -//! We're going to match on the top of the new pattern-stack, `p_1`. -//! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. -//! Then, the usefulness of `p_1` can be reduced to whether it is useful when -//! we ignore all the patterns in the first column of `P` that involve other constructors. -//! This is where `S(c, P)` comes in: -//! `U(P, p) := U(S(c, P), S(c, p))` -//! This special case is handled in `is_useful_specialized`. +//! We're going to match on the top of the new pattern-stack, `p_1`. +//! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. +//! Then, the usefulness of `p_1` can be reduced to whether it is useful when +//! we ignore all the patterns in the first column of `P` that involve other constructors. +//! This is where `S(c, P)` comes in: +//! `U(P, p) := U(S(c, P), S(c, p))` +//! This special case is handled in `is_useful_specialized`. //! -//! For example, if `P` is: -//! [ -//! [Some(true), _], -//! [None, 0], -//! ] -//! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only -//! matches values that row 2 doesn't. For row 1 however, we need to dig into the -//! arguments of `Some` to know whether some new value is covered. So we compute -//! `U([[true, _]], [false, 0])`. +//! For example, if `P` is: +//! [ +//! [Some(true), _], +//! [None, 0], +//! ] +//! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only +//! matches values that row 2 doesn't. For row 1 however, we need to dig into the +//! arguments of `Some` to know whether some new value is covered. So we compute +//! `U([[true, _]], [false, 0])`. //! -//! - If `p_1 == _`, then we look at the list of constructors that appear in the first -//! component of the rows of `P`: -//! + If there are some constructors that aren't present, then we might think that the -//! wildcard `_` is useful, since it covers those constructors that weren't covered -//! before. -//! That's almost correct, but only works if there were no wildcards in those first -//! components. So we need to check that `p` is useful with respect to the rows that -//! start with a wildcard, if there are any. This is where `D` comes in: -//! `U(P, p) := U(D(P), D(p))` +//! - If `p_1 == _`, then we look at the list of constructors that appear in the first +//! component of the rows of `P`: +//! + If there are some constructors that aren't present, then we might think that the +//! wildcard `_` is useful, since it covers those constructors that weren't covered +//! before. +//! That's almost correct, but only works if there were no wildcards in those first +//! components. So we need to check that `p` is useful with respect to the rows that +//! start with a wildcard, if there are any. This is where `D` comes in: +//! `U(P, p) := U(D(P), D(p))` //! -//! For example, if `P` is: -//! [ -//! [_, true, _], -//! [None, false, 1], -//! ] -//! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we -//! only had row 2, we'd know that `p` is useful. However row 1 starts with a -//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. +//! For example, if `P` is: +//! [ +//! [_, true, _], +//! [None, false, 1], +//! ] +//! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we +//! only had row 2, we'd know that `p` is useful. However row 1 starts with a +//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. //! -//! + Otherwise, all possible constructors (for the relevant type) are present. In this -//! case we must check whether the wildcard pattern covers any unmatched value. For -//! that, we can think of the `_` pattern as a big OR-pattern that covers all -//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for -//! example. The wildcard pattern is useful in this case if it is useful when -//! specialized to one of the possible constructors. So we compute: -//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` +//! + Otherwise, all possible constructors (for the relevant type) are present. In this +//! case we must check whether the wildcard pattern covers any unmatched value. For +//! that, we can think of the `_` pattern as a big OR-pattern that covers all +//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for +//! example. The wildcard pattern is useful in this case if it is useful when +//! specialized to one of the possible constructors. So we compute: +//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` //! -//! For example, if `P` is: -//! [ -//! [Some(true), _], -//! [None, false], -//! ] -//! and `p` is [_, false], both `None` and `Some` constructors appear in the first -//! components of `P`. We will therefore try popping both constructors in turn: we -//! compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]], -//! [false]) for the `None` constructor. The first case returns true, so we know that -//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched -//! before. +//! For example, if `P` is: +//! [ +//! [Some(true), _], +//! [None, false], +//! ] +//! and `p` is [_, false], both `None` and `Some` constructors appear in the first +//! components of `P`. We will therefore try popping both constructors in turn: we +//! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]], +//! [false])` for the `None` constructor. The first case returns true, so we know that +//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched +//! before. //! -//! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: -//! `U(P, p) := U(P, (r_1, p_2, .., p_n)) -//! || U(P, (r_2, p_2, .., p_n))` +//! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: +//! `U(P, p) := U(P, (r_1, p_2, .., p_n)) +//! || U(P, (r_2, p_2, .., p_n))` //! //! Modifications to the algorithm //! ------------------------------ From 2d9ed15c070cda189e2715eedc887b0e51de0233 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Jun 2020 11:00:51 +0200 Subject: [PATCH 56/92] update Miri --- src/tools/miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri b/src/tools/miri index 59619775ee44a..fd8101247749c 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 59619775ee44a5e0c875efffc4ca55ae96fca7dc +Subproject commit fd8101247749c5be6850d5cb5096f01a1867e5ba From f74a7d3ff1a080f4877a43096985b693d5949f55 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 30 Jun 2020 13:36:33 +0200 Subject: [PATCH 57/92] Clean up E0712 explanation --- src/librustc_error_codes/error_codes/E0712.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_error_codes/error_codes/E0712.md b/src/librustc_error_codes/error_codes/E0712.md index 89f60084f0a60..7e09210e7874c 100644 --- a/src/librustc_error_codes/error_codes/E0712.md +++ b/src/librustc_error_codes/error_codes/E0712.md @@ -1,5 +1,5 @@ -This error occurs because a borrow of a thread-local variable was made inside a -function which outlived the lifetime of the function. +A borrow of a thread-local variable was made inside a function which outlived +the lifetime of the function. Erroneous code example: From 8ee1dec77b89d6341a147d91af8733f8e0b5efc7 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Mon, 22 Jun 2020 00:54:46 +0200 Subject: [PATCH 58/92] Deny unsafe ops in unsafe fns, part 1 --- src/libcore/alloc/global.rs | 22 ++++++++++---- src/libcore/alloc/layout.rs | 3 +- src/libcore/alloc/mod.rs | 59 +++++++++++++++++++++++++++++-------- src/libcore/cell.rs | 8 ++++- src/libcore/char/convert.rs | 5 +++- src/libcore/char/methods.rs | 5 +++- src/libcore/convert/num.rs | 5 +++- src/libcore/hint.rs | 6 +++- src/libcore/intrinsics.rs | 14 +++++++-- src/libcore/lib.rs | 1 + src/libcore/pin.rs | 14 +++++++-- 11 files changed, 111 insertions(+), 31 deletions(-) diff --git a/src/libcore/alloc/global.rs b/src/libcore/alloc/global.rs index 147fe696ac02f..c198797e650f6 100644 --- a/src/libcore/alloc/global.rs +++ b/src/libcore/alloc/global.rs @@ -127,9 +127,12 @@ pub unsafe trait GlobalAlloc { #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); - let ptr = self.alloc(layout); + // SAFETY: the safety contract for `alloc` must be upheld by the caller. + let ptr = unsafe { self.alloc(layout) }; if !ptr.is_null() { - ptr::write_bytes(ptr, 0, size); + // SAFETY: as allocation succeeded, the region from `ptr` + // of size `size` is guaranteed to be valid for writes. + unsafe { ptr::write_bytes(ptr, 0, size) }; } ptr } @@ -187,11 +190,18 @@ pub unsafe trait GlobalAlloc { /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - let new_ptr = self.alloc(new_layout); + // SAFETY: the caller must ensure that the `new_size` does not overflow. + // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid. + let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; + // SAFETY: the caller must ensure that `new_layout` is greater than zero. + let new_ptr = unsafe { self.alloc(new_layout) }; if !new_ptr.is_null() { - ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size)); - self.dealloc(ptr, layout); + // SAFETY: the previously allocated block cannot overlap the newly allocated block. + // The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size)); + self.dealloc(ptr, layout); + } } new_ptr } diff --git a/src/libcore/alloc/layout.rs b/src/libcore/alloc/layout.rs index a09c2387d0de2..ae7ae7044655b 100644 --- a/src/libcore/alloc/layout.rs +++ b/src/libcore/alloc/layout.rs @@ -90,7 +90,8 @@ impl Layout { #[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { - Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } + // SAFETY: the caller must ensure that `align` is greater than zero. + Layout { size_: size, align_: unsafe { NonZeroUsize::new_unchecked(align) } } } /// The minimum size in bytes for a memory block of this layout. diff --git a/src/libcore/alloc/mod.rs b/src/libcore/alloc/mod.rs index 1346fbd481003..d00dbd2c34d56 100644 --- a/src/libcore/alloc/mod.rs +++ b/src/libcore/alloc/mod.rs @@ -1,6 +1,7 @@ //! Memory allocation APIs #![stable(feature = "alloc_module", since = "1.28.0")] +#![deny(unsafe_op_in_unsafe_fn)] mod global; mod layout; @@ -54,7 +55,9 @@ impl AllocInit { #[inline] #[unstable(feature = "allocator_api", issue = "32838")] pub unsafe fn init(self, memory: MemoryBlock) { - self.init_offset(memory, 0) + // SAFETY: the safety contract for `init_offset` must be + // upheld by the caller. + unsafe { self.init_offset(memory, 0) } } /// Initialize the memory block like specified by `init` at the specified `offset`. @@ -78,7 +81,10 @@ impl AllocInit { match self { AllocInit::Uninitialized => (), AllocInit::Zeroed => { - memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset) + // SAFETY: the caller must guarantee that `offset` is smaller than or equal to `memory.size`, + // so the memory from `memory.ptr + offset` of length `memory.size - offset` + // is guaranteed to be contaned in `memory` and thus valid for writes. + unsafe { memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset) } } } } @@ -281,11 +287,23 @@ pub unsafe trait AllocRef { return Ok(MemoryBlock { ptr, size }); } - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + let new_layout = + // SAFETY: the caller must ensure that the `new_size` does not overflow. + // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. + // The caller must ensure that `new_size` is greater than zero. + unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_memory = self.alloc(new_layout, init)?; - ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size); - self.dealloc(ptr, layout); - Ok(new_memory) + + // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new + // memory allocation are valid for reads and writes for `size` bytes. Also, because the old + // allocation wasn't yet deallocated, it cannot overlap `new_memory`. Thus, the call to + // `copy_nonoverlapping` is safe. + // The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size); + self.dealloc(ptr, layout); + Ok(new_memory) + } } } } @@ -356,11 +374,23 @@ pub unsafe trait AllocRef { return Ok(MemoryBlock { ptr, size }); } - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + let new_layout = + // SAFETY: the caller must ensure that the `new_size` does not overflow. + // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. + // The caller must ensure that `new_size` is greater than zero. + unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?; - ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size); - self.dealloc(ptr, layout); - Ok(new_memory) + + // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new + // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the + // old allocation wasn't yet deallocated, it cannot overlap `new_memory`. Thus, the call to + // `copy_nonoverlapping` is safe. + // The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size); + self.dealloc(ptr, layout); + Ok(new_memory) + } } } } @@ -386,7 +416,8 @@ where #[inline] unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - (**self).dealloc(ptr, layout) + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).dealloc(ptr, layout) } } #[inline] @@ -398,7 +429,8 @@ where placement: ReallocPlacement, init: AllocInit, ) -> Result { - (**self).grow(ptr, layout, new_size, placement, init) + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, layout, new_size, placement, init) } } #[inline] @@ -409,6 +441,7 @@ where new_size: usize, placement: ReallocPlacement, ) -> Result { - (**self).shrink(ptr, layout, new_size, placement) + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).shrink(ptr, layout, new_size, placement) } } } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c4293ed7bcfe2..caaf940b62cb2 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -187,6 +187,7 @@ //! #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; @@ -1005,7 +1006,12 @@ impl RefCell { #[inline] pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> { if !is_writing(self.borrow.get()) { - Ok(&*self.value.get()) + // SAFETY: We check that nobody is actively writing now, but it is + // the caller's responsibility to ensure that nobody writes until + // the returned reference is no longer in use. + // Also, `self.value.get()` refers to the value owned by `self` + // and is thus guaranteed to be valid for the lifetime of `self`. + Ok(unsafe { &*self.value.get() }) } else { Err(BorrowError { _private: () }) } diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index d7e39946148ed..001362ba1c375 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -1,5 +1,7 @@ //! Character conversions. +#![deny(unsafe_op_in_unsafe_fn)] + use crate::convert::TryFrom; use crate::fmt; use crate::mem::transmute; @@ -99,7 +101,8 @@ pub fn from_u32(i: u32) -> Option { #[inline] #[stable(feature = "char_from_unchecked", since = "1.5.0")] pub unsafe fn from_u32_unchecked(i: u32) -> char { - if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { transmute(i) } + // SAFETY: the caller must guarantee that `i` is a valid char value. + if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { unsafe { transmute(i) } } } #[stable(feature = "char_convert", since = "1.13.0")] diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index dd2f01c679f73..5a62c92694fad 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -1,5 +1,7 @@ //! impl char {} +#![deny(unsafe_op_in_unsafe_fn)] + use crate::slice; use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; @@ -183,7 +185,8 @@ impl char { #[unstable(feature = "assoc_char_funcs", reason = "recently added", issue = "71763")] #[inline] pub unsafe fn from_u32_unchecked(i: u32) -> char { - super::convert::from_u32_unchecked(i) + // SAFETY: the safety contract must be upheld by the caller. + unsafe { super::convert::from_u32_unchecked(i) } } /// Converts a digit in the given radix to a `char`. diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs index 46ba0a279b7ff..094618acc5885 100644 --- a/src/libcore/convert/num.rs +++ b/src/libcore/convert/num.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use super::{From, TryFrom}; use crate::num::TryFromIntError; @@ -28,7 +30,8 @@ macro_rules! impl_float_to_int { #[doc(hidden)] #[inline] unsafe fn to_int_unchecked(self) -> $Int { - crate::intrinsics::float_to_int_unchecked(self) + // SAFETY: the safety contract must be upheld by the caller. + unsafe { crate::intrinsics::float_to_int_unchecked(self) } } } )+ diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 0d794de5fe84b..fd2d443dde8d8 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -2,6 +2,8 @@ //! Hints to compiler that affects how code should be emitted or optimized. +#![deny(unsafe_op_in_unsafe_fn)] + use crate::intrinsics; /// Informs the compiler that this point in the code is not reachable, enabling @@ -46,7 +48,9 @@ use crate::intrinsics; #[inline] #[stable(feature = "unreachable", since = "1.27.0")] pub unsafe fn unreachable_unchecked() -> ! { - intrinsics::unreachable() + // SAFETY: the safety contract for `intrinsics::unreachable` must + // be upheld by the caller. + unsafe { intrinsics::unreachable() } } /// Emits a machine instruction hinting to the processor that it is running in busy-wait diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 5d09018759191..237c6e0545f8f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -53,6 +53,7 @@ issue = "none" )] #![allow(missing_docs)] +#![deny(unsafe_op_in_unsafe_fn)] use crate::marker::DiscriminantKind; use crate::mem; @@ -2097,7 +2098,10 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { // Not panicking to keep codegen impact smaller. abort(); } - copy_nonoverlapping(src, dst, count) + + // SAFETY: the safety contract for `copy_nonoverlapping` must be + // upheld by the caller. + unsafe { copy_nonoverlapping(src, dst, count) } } /// Copies `count * size_of::()` bytes from `src` to `dst`. The source @@ -2163,7 +2167,9 @@ pub unsafe fn copy(src: *const T, dst: *mut T, count: usize) { // Not panicking to keep codegen impact smaller. abort(); } - copy(src, dst, count) + + // SAFETY: the safety contract for `copy` must be upheld by the caller. + unsafe { copy(src, dst, count) } } /// Sets `count * size_of::()` bytes of memory starting at `dst` to @@ -2246,5 +2252,7 @@ pub unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { } debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); - write_bytes(dst, val, count) + + // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. + unsafe { write_bytes(dst, val, count) } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index aeb52bffbf24c..1459a6b2f16f7 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -148,6 +148,7 @@ #![feature(const_type_id)] #![feature(const_caller_location)] #![feature(no_niche)] // rust-lang/rust#68303 +#![feature(unsafe_block_in_unsafe_fn)] #[prelude_import] #[allow(unused)] diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 6f5bf7ad9da52..b042bed681e38 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -375,6 +375,7 @@ //! [`i32`]: ../../std/primitive.i32.html #![stable(feature = "pin", since = "1.33.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::cmp::{self, PartialEq, PartialOrd}; use crate::fmt; @@ -679,7 +680,10 @@ impl<'a, T: ?Sized> Pin<&'a T> { { let pointer = &*self.pointer; let new_pointer = func(pointer); - Pin::new_unchecked(new_pointer) + + // SAFETY: the safety contract for `new_unchecked` must be + // upheld by the caller. + unsafe { Pin::new_unchecked(new_pointer) } } /// Gets a shared reference out of a pin. @@ -769,9 +773,13 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { U: ?Sized, F: FnOnce(&mut T) -> &mut U, { - let pointer = Pin::get_unchecked_mut(self); + // SAFETY: the caller is responsible for not moving the + // value out of this reference. + let pointer = unsafe { Pin::get_unchecked_mut(self) }; let new_pointer = func(pointer); - Pin::new_unchecked(new_pointer) + // SAFETY: as the value of `this` is guaranteed to not have + // been moved out, this call to `new_unchecked` is safe. + unsafe { Pin::new_unchecked(new_pointer) } } } From 8a515e963cf2711192495802d7bbf2e49979cdf2 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Mon, 22 Jun 2020 19:25:39 +0200 Subject: [PATCH 59/92] Deny unsafe ops in unsafe fns, part 2 --- src/libcore/hash/sip.rs | 11 +++++--- src/libcore/iter/adapters/fuse.rs | 5 ++-- src/libcore/iter/adapters/mod.rs | 15 +++++++---- src/libcore/iter/adapters/zip.rs | 3 ++- src/libcore/iter/mod.rs | 1 + src/libcore/iter/range.rs | 30 ++++++++++++++++------ src/libcore/mem/manually_drop.rs | 9 +++++-- src/libcore/mem/maybe_uninit.rs | 42 +++++++++++++++++++++++-------- src/libcore/mem/mod.rs | 24 +++++++++++++----- 9 files changed, 103 insertions(+), 37 deletions(-) diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index ac058609f45ed..84148058d03f7 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -1,6 +1,7 @@ //! An implementation of SipHash. #![allow(deprecated)] // the types in this module are deprecated +#![deny(unsafe_op_in_unsafe_fn)] use crate::cmp; use crate::marker::PhantomData; @@ -130,15 +131,19 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { let mut i = 0; // current byte index (from LSB) in the output u64 let mut out = 0; if i + 3 < len { - out = load_int_le!(buf, start + i, u32) as u64; + // SAFETY: `i` cannot be greater than `len`, and the caller must guarantee + // that the index start..start+len is in bounds. + out = unsafe { load_int_le!(buf, start + i, u32) } as u64; i += 4; } if i + 1 < len { - out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8); + // SAFETY: same as above. + out |= (unsafe { load_int_le!(buf, start + i, u16) } as u64) << (i * 8); i += 2 } if i < len { - out |= (*buf.get_unchecked(start + i) as u64) << (i * 8); + // SAFETY: same as above. + out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8); i += 1; } debug_assert_eq!(i, len); diff --git a/src/libcore/iter/adapters/fuse.rs b/src/libcore/iter/adapters/fuse.rs index 502fc2e631502..d2e2fc04a2b76 100644 --- a/src/libcore/iter/adapters/fuse.rs +++ b/src/libcore/iter/adapters/fuse.rs @@ -178,9 +178,10 @@ where { unsafe fn get_unchecked(&mut self, i: usize) -> I::Item { match self.iter { - Some(ref mut iter) => iter.get_unchecked(i), + // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. + Some(ref mut iter) => unsafe { iter.get_unchecked(i) }, // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted. - None => intrinsics::unreachable(), + None => unsafe { intrinsics::unreachable() }, } } diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index 00529f0e2d54f..133643a0c7f03 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -272,7 +272,8 @@ where T: Copy, { unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - *self.it.get_unchecked(i) + // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. + unsafe { *self.it.get_unchecked(i) } } #[inline] @@ -402,7 +403,8 @@ where T: Clone, { default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - self.it.get_unchecked(i).clone() + // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. + unsafe { self.it.get_unchecked(i) }.clone() } #[inline] @@ -418,7 +420,8 @@ where T: Copy, { unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - *self.it.get_unchecked(i) + // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. + unsafe { *self.it.get_unchecked(i) } } #[inline] @@ -930,7 +933,8 @@ where F: FnMut(I::Item) -> B, { unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - (self.f)(self.iter.get_unchecked(i)) + // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. + (self.f)(unsafe { self.iter.get_unchecked(i) }) } #[inline] fn may_have_side_effect() -> bool { @@ -1392,7 +1396,8 @@ where I: TrustedRandomAccess, { unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) { - (self.count + i, self.iter.get_unchecked(i)) + // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. + (self.count + i, unsafe { self.iter.get_unchecked(i) }) } fn may_have_side_effect() -> bool { diff --git a/src/libcore/iter/adapters/zip.rs b/src/libcore/iter/adapters/zip.rs index e83d36a580f06..985e6561665c7 100644 --- a/src/libcore/iter/adapters/zip.rs +++ b/src/libcore/iter/adapters/zip.rs @@ -271,7 +271,8 @@ where B: TrustedRandomAccess, { unsafe fn get_unchecked(&mut self, i: usize) -> (A::Item, B::Item) { - (self.a.get_unchecked(i), self.b.get_unchecked(i)) + // SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`. + unsafe { (self.a.get_unchecked(i), self.b.get_unchecked(i)) } } fn may_have_side_effect() -> bool { diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 080b70c6368b2..4a1f6418bb5b3 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -309,6 +309,7 @@ //! [`min`]: trait.Iterator.html#method.min #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::ops::Try; diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index bd7e6cfa5a750..ee53b6a13f837 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -189,12 +189,14 @@ macro_rules! step_identical_methods { () => { #[inline] unsafe fn forward_unchecked(start: Self, n: usize) -> Self { - start.unchecked_add(n as Self) + // SAFETY: the caller has to guarantee that `start + n` doesn't overflow. + unsafe { start.unchecked_add(n as Self) } } #[inline] unsafe fn backward_unchecked(start: Self, n: usize) -> Self { - start.unchecked_sub(n as Self) + // SAFETY: the caller has to guarantee that `start - n` doesn't overflow. + unsafe { start.unchecked_sub(n as Self) } } #[inline] @@ -450,21 +452,33 @@ unsafe impl Step for char { #[inline] unsafe fn forward_unchecked(start: char, count: usize) -> char { let start = start as u32; - let mut res = Step::forward_unchecked(start, count); + // SAFETY: the caller must guarantee that this doesn't overflow + // the range of values for a char. + let mut res = unsafe { Step::forward_unchecked(start, count) }; if start < 0xD800 && 0xD800 <= res { - res = Step::forward_unchecked(res, 0x800); + // SAFETY: the caller must guarantee that this doesn't overflow + // the range of values for a char. + res = unsafe { Step::forward_unchecked(res, 0x800) }; } - char::from_u32_unchecked(res) + // SAFETY: because of the previous contract, this is guaranteed + // by the caller to be a valid char. + unsafe { char::from_u32_unchecked(res) } } #[inline] unsafe fn backward_unchecked(start: char, count: usize) -> char { let start = start as u32; - let mut res = Step::backward_unchecked(start, count); + // SAFETY: the caller must guarantee that this doesn't overflow + // the range of values for a char. + let mut res = unsafe { Step::backward_unchecked(start, count) }; if start >= 0xE000 && 0xE000 > res { - res = Step::backward_unchecked(res, 0x800); + // SAFETY: the caller must guarantee that this doesn't overflow + // the range of values for a char. + res = unsafe { Step::backward_unchecked(res, 0x800) }; } - char::from_u32_unchecked(res) + // SAFETY: because of the previous contract, this is guaranteed + // by the caller to be a valid char. + unsafe { char::from_u32_unchecked(res) } } } diff --git a/src/libcore/mem/manually_drop.rs b/src/libcore/mem/manually_drop.rs index 18767c482c77e..920f5e9c0bd28 100644 --- a/src/libcore/mem/manually_drop.rs +++ b/src/libcore/mem/manually_drop.rs @@ -122,7 +122,9 @@ impl ManuallyDrop { #[stable(feature = "manually_drop_take", since = "1.42.0")] #[inline] pub unsafe fn take(slot: &mut ManuallyDrop) -> T { - ptr::read(&slot.value) + // SAFETY: we are reading from a reference, which is guaranteed + // to be valid for reads. + unsafe { ptr::read(&slot.value) } } } @@ -152,7 +154,10 @@ impl ManuallyDrop { #[stable(feature = "manually_drop", since = "1.20.0")] #[inline] pub unsafe fn drop(slot: &mut ManuallyDrop) { - ptr::drop_in_place(&mut slot.value) + // SAFETY: we are dropping the value pointed to by a mutable reference + // which is guaranteed to be valid for writes. + // It is up to the caller to make sure that `slot` isn't dropped again. + unsafe { ptr::drop_in_place(&mut slot.value) } } } diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 499016545e967..7732525a0fc28 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -494,8 +494,12 @@ impl MaybeUninit { #[inline(always)] #[rustc_diagnostic_item = "assume_init"] pub unsafe fn assume_init(self) -> T { - intrinsics::assert_inhabited::(); - ManuallyDrop::into_inner(self.value) + // SAFETY: the caller must guarantee that `self` is initialized. + // This also means that `self` must be a `value` variant. + unsafe { + intrinsics::assert_inhabited::(); + ManuallyDrop::into_inner(self.value) + } } /// Reads the value from the `MaybeUninit` container. The resulting `T` is subject @@ -558,8 +562,12 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] pub unsafe fn read(&self) -> T { - intrinsics::assert_inhabited::(); - self.as_ptr().read() + // SAFETY: the caller must guarantee that `self` is initialized. + // Reading from `self.as_ptr()` is safe since `self` should be initialized. + unsafe { + intrinsics::assert_inhabited::(); + self.as_ptr().read() + } } /// Gets a shared reference to the contained value. @@ -620,8 +628,12 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_ref(&self) -> &T { - intrinsics::assert_inhabited::(); - &*self.value + // SAFETY: the caller must guarantee that `self` is initialized. + // This also means that `self` must be a `value` variant. + unsafe { + intrinsics::assert_inhabited::(); + &*self.value + } } /// Gets a mutable (unique) reference to the contained value. @@ -738,8 +750,12 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] pub unsafe fn get_mut(&mut self) -> &mut T { - intrinsics::assert_inhabited::(); - &mut *self.value + // SAFETY: the caller must guarantee that `self` is initialized. + // This also means that `self` must be a `value` variant. + unsafe { + intrinsics::assert_inhabited::(); + &mut *self.value + } } /// Assuming all the elements are initialized, get a slice to them. @@ -752,7 +768,11 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_slice_assume_init", issue = "none")] #[inline(always)] pub unsafe fn slice_get_ref(slice: &[Self]) -> &[T] { - &*(slice as *const [Self] as *const [T]) + // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that + // `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`. + // The pointer obtained is valid since it refers to memory owned by `slice` which is a + // reference and thus guaranteed to be valid for reads. + unsafe { &*(slice as *const [Self] as *const [T]) } } /// Assuming all the elements are initialized, get a mutable slice to them. @@ -765,7 +785,9 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_slice_assume_init", issue = "none")] #[inline(always)] pub unsafe fn slice_get_mut(slice: &mut [Self]) -> &mut [T] { - &mut *(slice as *mut [Self] as *mut [T]) + // SAFETY: similar to safety notes for `slice_get_ref`, but we have a + // mutable reference which is also guaranteed to be valid for writes. + unsafe { &mut *(slice as *mut [Self] as *mut [T]) } } /// Gets a pointer to the first element of the array. diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 46e6ea7cd1866..20ea83fd063c6 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -4,6 +4,7 @@ //! types, initializing and manipulating memory. #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::clone; use crate::cmp; @@ -623,8 +624,11 @@ pub const fn needs_drop() -> bool { #[allow(deprecated)] #[rustc_diagnostic_item = "mem_zeroed"] pub unsafe fn zeroed() -> T { - intrinsics::assert_zero_valid::(); - MaybeUninit::zeroed().assume_init() + // SAFETY: the caller must guarantee that an all-zero value is valid for `T`. + unsafe { + intrinsics::assert_zero_valid::(); + MaybeUninit::zeroed().assume_init() + } } /// Bypasses Rust's normal memory-initialization checks by pretending to @@ -656,8 +660,11 @@ pub unsafe fn zeroed() -> T { #[allow(deprecated)] #[rustc_diagnostic_item = "mem_uninitialized"] pub unsafe fn uninitialized() -> T { - intrinsics::assert_uninit_valid::(); - MaybeUninit::uninit().assume_init() + // SAFETY: the caller must guarantee that an unitialized value is valid for `T`. + unsafe { + intrinsics::assert_uninit_valid::(); + MaybeUninit::uninit().assume_init() + } } /// Swaps the values at two mutable locations, without deinitializing either one. @@ -922,9 +929,14 @@ pub fn drop(_x: T) {} pub unsafe fn transmute_copy(src: &T) -> U { // If U has a higher alignment requirement, src may not be suitably aligned. if align_of::() > align_of::() { - ptr::read_unaligned(src as *const T as *const U) + // SAFETY: `src` is a reference which is guaranteed to be valid for reads. + // The caller must guarantee that the actual transmutation is safe. + unsafe { ptr::read_unaligned(src as *const T as *const U) } } else { - ptr::read(src as *const T as *const U) + // SAFETY: `src` is a reference which is guaranteed to be valid for reads. + // We just checked that `src as *const U` was properly aligned. + // The caller must guarantee that the actual transmutation is safe. + unsafe { ptr::read(src as *const T as *const U) } } } From ac7539c6d1036e42e84d388a57a656c420cb9eee Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 24 Jun 2020 13:15:37 +0200 Subject: [PATCH 60/92] Deny unsafe ops in unsafe fns, part 3 --- src/libcore/num/f32.rs | 5 +- src/libcore/num/f64.rs | 5 +- src/libcore/num/mod.rs | 28 +++- src/libcore/sync/atomic.rs | 254 ++++++++++++++++++++++--------------- src/libcore/tests/lib.rs | 2 + 5 files changed, 181 insertions(+), 113 deletions(-) diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 6313de31ce4d5..028beb86e68ba 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -9,6 +9,7 @@ //! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::convert::FloatToInt; #[cfg(not(test))] @@ -629,7 +630,9 @@ impl f32 { where Self: FloatToInt, { - FloatToInt::::to_int_unchecked(self) + // SAFETY: the caller must uphold the safety contract for + // `FloatToInt::to_int_unchecked`. + unsafe { FloatToInt::::to_int_unchecked(self) } } /// Raw transmutation to `u32`. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d42e5392c5863..74e38c128b377 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -9,6 +9,7 @@ //! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::convert::FloatToInt; #[cfg(not(test))] @@ -643,7 +644,9 @@ impl f64 { where Self: FloatToInt, { - FloatToInt::::to_int_unchecked(self) + // SAFETY: the caller must uphold the safety contract for + // `FloatToInt::to_int_unchecked`. + unsafe { FloatToInt::::to_int_unchecked(self) } } /// Raw transmutation to `u64`. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index d36da90f2adc9..918eea7acb3ad 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3,6 +3,7 @@ //! Numeric traits and functions for the built-in numeric types. #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::convert::Infallible; use crate::fmt; @@ -74,7 +75,8 @@ assert_eq!(size_of::>(), size_of::<", s #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { - Self(n) + // SAFETY: this is guaranteed to be safe by the caller. + unsafe { Self(n) } } /// Creates a non-zero if the given value is not zero. @@ -762,7 +764,9 @@ cannot occur. This results in undefined behavior when `self + rhs > ", stringify without modifying the original"] #[inline] pub unsafe fn unchecked_add(self, rhs: Self) -> Self { - intrinsics::unchecked_add(self, rhs) + // SAFETY: the caller must uphold the safety contract for + // `unchecked_add`. + unsafe { intrinsics::unchecked_add(self, rhs) } } } @@ -804,7 +808,9 @@ cannot occur. This results in undefined behavior when `self - rhs > ", stringify without modifying the original"] #[inline] pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { - intrinsics::unchecked_sub(self, rhs) + // SAFETY: the caller must uphold the safety contract for + // `unchecked_sub`. + unsafe { intrinsics::unchecked_sub(self, rhs) } } } @@ -846,7 +852,9 @@ cannot occur. This results in undefined behavior when `self * rhs > ", stringify without modifying the original"] #[inline] pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { - intrinsics::unchecked_mul(self, rhs) + // SAFETY: the caller must uphold the safety contract for + // `unchecked_mul`. + unsafe { intrinsics::unchecked_mul(self, rhs) } } } @@ -2998,7 +3006,9 @@ cannot occur. This results in undefined behavior when `self + rhs > ", stringify without modifying the original"] #[inline] pub unsafe fn unchecked_add(self, rhs: Self) -> Self { - intrinsics::unchecked_add(self, rhs) + // SAFETY: the caller must uphold the safety contract for + // `unchecked_add`. + unsafe { intrinsics::unchecked_add(self, rhs) } } } @@ -3038,7 +3048,9 @@ cannot occur. This results in undefined behavior when `self - rhs > ", stringify without modifying the original"] #[inline] pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { - intrinsics::unchecked_sub(self, rhs) + // SAFETY: the caller must uphold the safety contract for + // `unchecked_sub`. + unsafe { intrinsics::unchecked_sub(self, rhs) } } } @@ -3078,7 +3090,9 @@ cannot occur. This results in undefined behavior when `self * rhs > ", stringify without modifying the original"] #[inline] pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { - intrinsics::unchecked_mul(self, rhs) + // SAFETY: the caller must uphold the safety contract for + // `unchecked_mul`. + unsafe { intrinsics::unchecked_mul(self, rhs) } } } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 1cd68f2881b7c..359c39a065f51 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -115,6 +115,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(unused_imports))] +#![deny(unsafe_op_in_unsafe_fn)] use self::Ordering::*; @@ -2335,35 +2336,44 @@ fn strongest_failure_ordering(order: Ordering) -> Ordering { #[inline] unsafe fn atomic_store(dst: *mut T, val: T, order: Ordering) { - match order { - Release => intrinsics::atomic_store_rel(dst, val), - Relaxed => intrinsics::atomic_store_relaxed(dst, val), - SeqCst => intrinsics::atomic_store(dst, val), - Acquire => panic!("there is no such thing as an acquire store"), - AcqRel => panic!("there is no such thing as an acquire/release store"), + // SAFETY: the caller must uphold the safety contract for `atomic_store`. + unsafe { + match order { + Release => intrinsics::atomic_store_rel(dst, val), + Relaxed => intrinsics::atomic_store_relaxed(dst, val), + SeqCst => intrinsics::atomic_store(dst, val), + Acquire => panic!("there is no such thing as an acquire store"), + AcqRel => panic!("there is no such thing as an acquire/release store"), + } } } #[inline] unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_load_acq(dst), - Relaxed => intrinsics::atomic_load_relaxed(dst), - SeqCst => intrinsics::atomic_load(dst), - Release => panic!("there is no such thing as a release load"), - AcqRel => panic!("there is no such thing as an acquire/release load"), + // SAFETY: the caller must uphold the safety contract for `atomic_load`. + unsafe { + match order { + Acquire => intrinsics::atomic_load_acq(dst), + Relaxed => intrinsics::atomic_load_relaxed(dst), + SeqCst => intrinsics::atomic_load(dst), + Release => panic!("there is no such thing as a release load"), + AcqRel => panic!("there is no such thing as an acquire/release load"), + } } } #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_xchg_acq(dst, val), - Release => intrinsics::atomic_xchg_rel(dst, val), - AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), - Relaxed => intrinsics::atomic_xchg_relaxed(dst, val), - SeqCst => intrinsics::atomic_xchg(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_swap`. + unsafe { + match order { + Acquire => intrinsics::atomic_xchg_acq(dst, val), + Release => intrinsics::atomic_xchg_rel(dst, val), + AcqRel => intrinsics::atomic_xchg_acqrel(dst, val), + Relaxed => intrinsics::atomic_xchg_relaxed(dst, val), + SeqCst => intrinsics::atomic_xchg(dst, val), + } } } @@ -2371,12 +2381,15 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_xadd_acq(dst, val), - Release => intrinsics::atomic_xadd_rel(dst, val), - AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), - Relaxed => intrinsics::atomic_xadd_relaxed(dst, val), - SeqCst => intrinsics::atomic_xadd(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_add`. + unsafe { + match order { + Acquire => intrinsics::atomic_xadd_acq(dst, val), + Release => intrinsics::atomic_xadd_rel(dst, val), + AcqRel => intrinsics::atomic_xadd_acqrel(dst, val), + Relaxed => intrinsics::atomic_xadd_relaxed(dst, val), + SeqCst => intrinsics::atomic_xadd(dst, val), + } } } @@ -2384,12 +2397,15 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_xsub_acq(dst, val), - Release => intrinsics::atomic_xsub_rel(dst, val), - AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), - Relaxed => intrinsics::atomic_xsub_relaxed(dst, val), - SeqCst => intrinsics::atomic_xsub(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_sub`. + unsafe { + match order { + Acquire => intrinsics::atomic_xsub_acq(dst, val), + Release => intrinsics::atomic_xsub_rel(dst, val), + AcqRel => intrinsics::atomic_xsub_acqrel(dst, val), + Relaxed => intrinsics::atomic_xsub_relaxed(dst, val), + SeqCst => intrinsics::atomic_xsub(dst, val), + } } } @@ -2402,19 +2418,22 @@ unsafe fn atomic_compare_exchange( success: Ordering, failure: Ordering, ) -> Result { - let (val, ok) = match (success, failure) { - (Acquire, Acquire) => intrinsics::atomic_cxchg_acq(dst, old, new), - (Release, Relaxed) => intrinsics::atomic_cxchg_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new), - (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new), - (Acquire, Relaxed) => intrinsics::atomic_cxchg_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), - (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), - (_, Release) => panic!("there is no such thing as a release failure ordering"), - _ => panic!("a failure ordering can't be stronger than a success ordering"), + // SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange`. + let (val, ok) = unsafe { + match (success, failure) { + (Acquire, Acquire) => intrinsics::atomic_cxchg_acq(dst, old, new), + (Release, Relaxed) => intrinsics::atomic_cxchg_rel(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new), + (Relaxed, Relaxed) => intrinsics::atomic_cxchg_relaxed(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchg(dst, old, new), + (Acquire, Relaxed) => intrinsics::atomic_cxchg_acq_failrelaxed(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchg_acqrel_failrelaxed(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchg_failrelaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchg_failacq(dst, old, new), + (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), + (_, Release) => panic!("there is no such thing as a release failure ordering"), + _ => panic!("a failure ordering can't be stronger than a success ordering"), + } }; if ok { Ok(val) } else { Err(val) } } @@ -2428,19 +2447,22 @@ unsafe fn atomic_compare_exchange_weak( success: Ordering, failure: Ordering, ) -> Result { - let (val, ok) = match (success, failure) { - (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acq(dst, old, new), - (Release, Relaxed) => intrinsics::atomic_cxchgweak_rel(dst, old, new), - (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel(dst, old, new), - (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed(dst, old, new), - (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak(dst, old, new), - (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acq_failrelaxed(dst, old, new), - (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_failrelaxed(dst, old, new), - (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_failrelaxed(dst, old, new), - (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_failacq(dst, old, new), - (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), - (_, Release) => panic!("there is no such thing as a release failure ordering"), - _ => panic!("a failure ordering can't be stronger than a success ordering"), + // SAFETY: the caller must uphold the safety contract for `atomic_compare_exchange_weak`. + let (val, ok) = unsafe { + match (success, failure) { + (Acquire, Acquire) => intrinsics::atomic_cxchgweak_acq(dst, old, new), + (Release, Relaxed) => intrinsics::atomic_cxchgweak_rel(dst, old, new), + (AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel(dst, old, new), + (Relaxed, Relaxed) => intrinsics::atomic_cxchgweak_relaxed(dst, old, new), + (SeqCst, SeqCst) => intrinsics::atomic_cxchgweak(dst, old, new), + (Acquire, Relaxed) => intrinsics::atomic_cxchgweak_acq_failrelaxed(dst, old, new), + (AcqRel, Relaxed) => intrinsics::atomic_cxchgweak_acqrel_failrelaxed(dst, old, new), + (SeqCst, Relaxed) => intrinsics::atomic_cxchgweak_failrelaxed(dst, old, new), + (SeqCst, Acquire) => intrinsics::atomic_cxchgweak_failacq(dst, old, new), + (_, AcqRel) => panic!("there is no such thing as an acquire/release failure ordering"), + (_, Release) => panic!("there is no such thing as a release failure ordering"), + _ => panic!("a failure ordering can't be stronger than a success ordering"), + } }; if ok { Ok(val) } else { Err(val) } } @@ -2448,48 +2470,60 @@ unsafe fn atomic_compare_exchange_weak( #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_and_acq(dst, val), - Release => intrinsics::atomic_and_rel(dst, val), - AcqRel => intrinsics::atomic_and_acqrel(dst, val), - Relaxed => intrinsics::atomic_and_relaxed(dst, val), - SeqCst => intrinsics::atomic_and(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_and` + unsafe { + match order { + Acquire => intrinsics::atomic_and_acq(dst, val), + Release => intrinsics::atomic_and_rel(dst, val), + AcqRel => intrinsics::atomic_and_acqrel(dst, val), + Relaxed => intrinsics::atomic_and_relaxed(dst, val), + SeqCst => intrinsics::atomic_and(dst, val), + } } } #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_nand_acq(dst, val), - Release => intrinsics::atomic_nand_rel(dst, val), - AcqRel => intrinsics::atomic_nand_acqrel(dst, val), - Relaxed => intrinsics::atomic_nand_relaxed(dst, val), - SeqCst => intrinsics::atomic_nand(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_nand` + unsafe { + match order { + Acquire => intrinsics::atomic_nand_acq(dst, val), + Release => intrinsics::atomic_nand_rel(dst, val), + AcqRel => intrinsics::atomic_nand_acqrel(dst, val), + Relaxed => intrinsics::atomic_nand_relaxed(dst, val), + SeqCst => intrinsics::atomic_nand(dst, val), + } } } #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_or_acq(dst, val), - Release => intrinsics::atomic_or_rel(dst, val), - AcqRel => intrinsics::atomic_or_acqrel(dst, val), - Relaxed => intrinsics::atomic_or_relaxed(dst, val), - SeqCst => intrinsics::atomic_or(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_or` + unsafe { + match order { + Acquire => intrinsics::atomic_or_acq(dst, val), + Release => intrinsics::atomic_or_rel(dst, val), + AcqRel => intrinsics::atomic_or_acqrel(dst, val), + Relaxed => intrinsics::atomic_or_relaxed(dst, val), + SeqCst => intrinsics::atomic_or(dst, val), + } } } #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_xor_acq(dst, val), - Release => intrinsics::atomic_xor_rel(dst, val), - AcqRel => intrinsics::atomic_xor_acqrel(dst, val), - Relaxed => intrinsics::atomic_xor_relaxed(dst, val), - SeqCst => intrinsics::atomic_xor(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_xor` + unsafe { + match order { + Acquire => intrinsics::atomic_xor_acq(dst, val), + Release => intrinsics::atomic_xor_rel(dst, val), + AcqRel => intrinsics::atomic_xor_acqrel(dst, val), + Relaxed => intrinsics::atomic_xor_relaxed(dst, val), + SeqCst => intrinsics::atomic_xor(dst, val), + } } } @@ -2497,12 +2531,15 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_max(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_max_acq(dst, val), - Release => intrinsics::atomic_max_rel(dst, val), - AcqRel => intrinsics::atomic_max_acqrel(dst, val), - Relaxed => intrinsics::atomic_max_relaxed(dst, val), - SeqCst => intrinsics::atomic_max(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_max` + unsafe { + match order { + Acquire => intrinsics::atomic_max_acq(dst, val), + Release => intrinsics::atomic_max_rel(dst, val), + AcqRel => intrinsics::atomic_max_acqrel(dst, val), + Relaxed => intrinsics::atomic_max_relaxed(dst, val), + SeqCst => intrinsics::atomic_max(dst, val), + } } } @@ -2510,12 +2547,15 @@ unsafe fn atomic_max(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_min(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_min_acq(dst, val), - Release => intrinsics::atomic_min_rel(dst, val), - AcqRel => intrinsics::atomic_min_acqrel(dst, val), - Relaxed => intrinsics::atomic_min_relaxed(dst, val), - SeqCst => intrinsics::atomic_min(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_min` + unsafe { + match order { + Acquire => intrinsics::atomic_min_acq(dst, val), + Release => intrinsics::atomic_min_rel(dst, val), + AcqRel => intrinsics::atomic_min_acqrel(dst, val), + Relaxed => intrinsics::atomic_min_relaxed(dst, val), + SeqCst => intrinsics::atomic_min(dst, val), + } } } @@ -2523,12 +2563,15 @@ unsafe fn atomic_min(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_umax(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_umax_acq(dst, val), - Release => intrinsics::atomic_umax_rel(dst, val), - AcqRel => intrinsics::atomic_umax_acqrel(dst, val), - Relaxed => intrinsics::atomic_umax_relaxed(dst, val), - SeqCst => intrinsics::atomic_umax(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_umax` + unsafe { + match order { + Acquire => intrinsics::atomic_umax_acq(dst, val), + Release => intrinsics::atomic_umax_rel(dst, val), + AcqRel => intrinsics::atomic_umax_acqrel(dst, val), + Relaxed => intrinsics::atomic_umax_relaxed(dst, val), + SeqCst => intrinsics::atomic_umax(dst, val), + } } } @@ -2536,12 +2579,15 @@ unsafe fn atomic_umax(dst: *mut T, val: T, order: Ordering) -> T { #[inline] #[cfg(target_has_atomic = "8")] unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_umin_acq(dst, val), - Release => intrinsics::atomic_umin_rel(dst, val), - AcqRel => intrinsics::atomic_umin_acqrel(dst, val), - Relaxed => intrinsics::atomic_umin_relaxed(dst, val), - SeqCst => intrinsics::atomic_umin(dst, val), + // SAFETY: the caller must uphold the safety contract for `atomic_umin` + unsafe { + match order { + Acquire => intrinsics::atomic_umin_acq(dst, val), + Release => intrinsics::atomic_umin_rel(dst, val), + AcqRel => intrinsics::atomic_umin_acqrel(dst, val), + Relaxed => intrinsics::atomic_umin_relaxed(dst, val), + SeqCst => intrinsics::atomic_umin(dst, val), + } } } diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index c60ce8ec837d5..68a5e20a66fdc 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -44,6 +44,8 @@ #![feature(option_unwrap_none)] #![feature(peekable_next_if)] #![feature(partition_point)] +#![feature(unsafe_block_in_unsafe_fn)] +#![deny(unsafe_op_in_unsafe_fn)] extern crate test; From c68f478131a94f5a69d91db1af35cb506f673ec2 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 25 Jun 2020 18:46:59 +0200 Subject: [PATCH 61/92] Deny unsafe ops in unsafe fns, part 4 --- src/libcore/slice/rotate.rs | 48 ++++++++++------- src/libcore/str/mod.rs | 100 ++++++++++++++++++++++++++++-------- 2 files changed, 108 insertions(+), 40 deletions(-) diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index f73e14f27e092..7bdd7d009e156 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -1,3 +1,7 @@ +// ignore-tidy-undocumented-unsafe + +#![deny(unsafe_op_in_unsafe_fn)] + use crate::cmp; use crate::mem::{self, MaybeUninit}; use crate::ptr; @@ -77,9 +81,9 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) // the way until about `left + right == 32`, but the worst case performance breaks even // around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4 // `usize`s, this algorithm also outperforms other algorithms. - let x = mid.sub(left); + let x = unsafe { mid.sub(left) }; // beginning of first round - let mut tmp: T = x.read(); + let mut tmp: T = unsafe { x.read() }; let mut i = right; // `gcd` can be found before hand by calculating `gcd(left + right, right)`, // but it is faster to do one loop which calculates the gcd as a side effect, then @@ -90,7 +94,7 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) // the very end. This is possibly due to the fact that swapping or replacing temporaries // uses only one memory address in the loop instead of needing to manage two. loop { - tmp = x.add(i).replace(tmp); + tmp = unsafe { x.add(i).replace(tmp) }; // instead of incrementing `i` and then checking if it is outside the bounds, we // check if `i` will go outside the bounds on the next increment. This prevents // any wrapping of pointers or `usize`. @@ -98,7 +102,7 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) i -= left; if i == 0 { // end of first round - x.write(tmp); + unsafe { x.write(tmp) }; break; } // this conditional must be here if `left + right >= 15` @@ -111,14 +115,14 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) } // finish the chunk with more rounds for start in 1..gcd { - tmp = x.add(start).read(); + tmp = unsafe { x.add(start).read() }; i = start + right; loop { - tmp = x.add(i).replace(tmp); + tmp = unsafe { x.add(i).replace(tmp) }; if i >= left { i -= left; if i == start { - x.add(start).write(tmp); + unsafe { x.add(start).write(tmp) }; break; } } else { @@ -133,15 +137,19 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) // The `[T; 0]` here is to ensure this is appropriately aligned for T let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit(); let buf = rawarray.as_mut_ptr() as *mut T; - let dim = mid.sub(left).add(right); + let dim = unsafe { mid.sub(left).add(right) }; if left <= right { - ptr::copy_nonoverlapping(mid.sub(left), buf, left); - ptr::copy(mid, mid.sub(left), right); - ptr::copy_nonoverlapping(buf, dim, left); + unsafe { + ptr::copy_nonoverlapping(mid.sub(left), buf, left); + ptr::copy(mid, mid.sub(left), right); + ptr::copy_nonoverlapping(buf, dim, left); + } } else { - ptr::copy_nonoverlapping(mid, buf, right); - ptr::copy(mid.sub(left), dim, left); - ptr::copy_nonoverlapping(buf, mid.sub(left), right); + unsafe { + ptr::copy_nonoverlapping(mid, buf, right); + ptr::copy(mid.sub(left), dim, left); + ptr::copy_nonoverlapping(buf, mid.sub(left), right); + } } return; } else if left >= right { @@ -150,8 +158,10 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) // of this algorithm would be, and swapping using that last chunk instead of swapping // adjacent chunks like this algorithm is doing, but this way is still faster. loop { - ptr::swap_nonoverlapping(mid.sub(right), mid, right); - mid = mid.sub(right); + unsafe { + ptr::swap_nonoverlapping(mid.sub(right), mid, right); + mid = mid.sub(right); + } left -= right; if left < right { break; @@ -160,8 +170,10 @@ pub unsafe fn ptr_rotate(mut left: usize, mut mid: *mut T, mut right: usize) } else { // Algorithm 3, `left < right` loop { - ptr::swap_nonoverlapping(mid.sub(left), mid, left); - mid = mid.add(left); + unsafe { + ptr::swap_nonoverlapping(mid.sub(left), mid, left); + mid = mid.add(left); + } right -= left; if right < left { break; diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 6c4b28499a60b..cbbeaa81d4572 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -7,6 +7,7 @@ //! [`std::str`]: ../../std/str/index.html #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use self::pattern::Pattern; use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; @@ -419,7 +420,11 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { - &*(v as *const [u8] as *const str) + // SAFETY: the caller must guarantee that the bytes `v` + // are valid UTF-8, thus the cast to `*const str` is safe. + // Also, the pointer dereference is safe because that pointer + // comes from a reference which is guaranteed to be valid for reads. + unsafe { &*(v as *const [u8] as *const str) } } /// Converts a slice of bytes to a string slice without checking @@ -444,7 +449,11 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { #[inline] #[stable(feature = "str_mut_extras", since = "1.20.0")] pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { - &mut *(v as *mut [u8] as *mut str) + // SAFETY: the caller must guarantee that the bytes `v` + // are valid UTF-8, thus the cast to `*mut str` is safe. + // Also, the pointer dereference is safe because that pointer + // comes from a reference which is guaranteed to be valid for writes. + unsafe { &mut *(v as *mut [u8] as *mut str) } } #[stable(feature = "rust1", since = "1.0.0")] @@ -867,7 +876,9 @@ unsafe impl TrustedLen for Bytes<'_> {} #[doc(hidden)] unsafe impl TrustedRandomAccess for Bytes<'_> { unsafe fn get_unchecked(&mut self, i: usize) -> u8 { - self.0.get_unchecked(i) + // SAFETY: the caller must uphold the safety contract + // for `TrustedRandomAccess::get_unchecked`. + unsafe { self.0.get_unchecked(i) } } fn may_have_side_effect() -> bool { false @@ -1904,15 +1915,27 @@ mod traits { } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - let ptr = slice.as_ptr().add(self.start); + // SAFETY: the caller guarantees that `self` is in bounds of `slice` + // which satisfies all the conditions for `add`. + let ptr = unsafe { slice.as_ptr().add(self.start) }; let len = self.end - self.start; - super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, + // we can safely construct a subslice with `from_raw_parts` and use it + // since we return a shared thus immutable reference. + // The call to `from_utf8_unchecked` is safe since the data comes from + // a `str` which is guaranteed to be valid utf8, since the caller + // must guarantee that `self.start` and `self.end` are char boundaries. + unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - let ptr = slice.as_mut_ptr().add(self.start); + // SAFETY: see comments for `get_unchecked`. + let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; let len = self.end - self.start; - super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) + // SAFETY: mostly identical to the comments for `get_unchecked`, except that we + // can return a mutable reference since the caller passed a mutable reference + // and is thus guaranteed to have exclusive write access to `slice`. + unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) } } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1974,12 +1997,21 @@ mod traits { #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { let ptr = slice.as_ptr(); - super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) + // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, + // we can safely construct a subslice with `from_raw_parts` and use it + // since we return a shared thus immutable reference. + // The call to `from_utf8_unchecked` is safe since the data comes from + // a `str` which is guaranteed to be valid utf8, since the caller + // must guarantee that `self.end` is a char boundary. + unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { let ptr = slice.as_mut_ptr(); - super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) + // SAFETY: mostly identical to `get_unchecked`, except that we can safely + // return a mutable reference since the caller passed a mutable reference + // and is thus guaranteed to have exclusive write access to `slice`. + unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) } } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2036,15 +2068,27 @@ mod traits { } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - let ptr = slice.as_ptr().add(self.start); + // SAFETY: the caller guarantees that `self` is in bounds of `slice` + // which satisfies all the conditions for `add`. + let ptr = unsafe { slice.as_ptr().add(self.start) }; let len = slice.len() - self.start; - super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + // SAFETY: as the caller guarantees that `self` is in bounds of `slice`, + // we can safely construct a subslice with `from_raw_parts` and use it + // since we return a shared thus immutable reference. + // The call to `from_utf8_unchecked` is safe since the data comes from + // a `str` which is guaranteed to be valid utf8, since the caller + // must guarantee that `self.start` is a char boundary. + unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - let ptr = slice.as_mut_ptr().add(self.start); + // SAFETY: identical to `get_unchecked`. + let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; let len = slice.len() - self.start; - super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) + // SAFETY: mostly identical to `get_unchecked`, except that we can safely + // return a mutable reference since the caller passed a mutable reference + // and is thus guaranteed to have exclusive write access to `slice`. + unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) } } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2099,11 +2143,13 @@ mod traits { } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - (*self.start()..self.end() + 1).get_unchecked(slice) + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - (*self.start()..self.end() + 1).get_unchecked_mut(slice) + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2148,11 +2194,13 @@ mod traits { } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - (..self.end + 1).get_unchecked(slice) + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { (..self.end + 1).get_unchecked(slice) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - (..self.end + 1).get_unchecked_mut(slice) + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { (..self.end + 1).get_unchecked_mut(slice) } } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -2373,7 +2421,11 @@ impl str { #[stable(feature = "str_mut_extras", since = "1.20.0")] #[inline(always)] pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - &mut *(self as *mut str as *mut [u8]) + // SAFETY: the cast from `&str` to `&[u8]` is safe since `str` + // has the same layout as `&[u8]` (only libstd can make this guarantee). + // The pointer dereference is safe since it comes from a mutable reference which + // is guaranteed to be valid for writes. + unsafe { &mut *(self as *mut str as *mut [u8]) } } /// Converts a string slice to a raw pointer. @@ -2509,7 +2561,8 @@ impl str { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - i.get_unchecked(self) + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { i.get_unchecked(self) } } /// Returns a mutable, unchecked subslice of `str`. @@ -2541,7 +2594,8 @@ impl str { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - i.get_unchecked_mut(self) + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { i.get_unchecked_mut(self) } } /// Creates a string slice from another string slice, bypassing safety @@ -2591,7 +2645,8 @@ impl str { #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - (begin..end).get_unchecked(self) + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { (begin..end).get_unchecked(self) } } /// Creates a string slice from another string slice, bypassing safety @@ -2622,7 +2677,8 @@ impl str { #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - (begin..end).get_unchecked_mut(self) + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { (begin..end).get_unchecked_mut(self) } } /// Divide one string slice into two at an index. From c225e5c5cb1200f46b83752e160b489eba1cd597 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 17 Jun 2020 11:05:30 -0700 Subject: [PATCH 62/92] Provide more information on duplicate lang item error. --- .../rmeta/decoder/cstore_impl.rs | 5 +++++ src/librustc_middle/middle/cstore.rs | 1 + src/librustc_middle/ty/context.rs | 9 ++++++++ src/librustc_passes/lang_items.rs | 21 +++++++++++++++++++ src/test/ui/duplicate_entry_error.rs | 1 + src/test/ui/duplicate_entry_error.stderr | 4 +++- src/test/ui/error-codes/E0152.rs | 1 + src/test/ui/error-codes/E0152.stderr | 4 +++- .../ui/panic-handler/panic-handler-std.rs | 1 + .../ui/panic-handler/panic-handler-std.stderr | 6 ++++-- 10 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index 1b168bf01178c..3472d8987c65c 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -27,6 +27,7 @@ use rustc_span::symbol::{Ident, Symbol}; use rustc_data_structures::sync::Lrc; use smallvec::SmallVec; use std::any::Any; +use std::path::PathBuf; macro_rules! provide { (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, @@ -513,4 +514,8 @@ impl CrateStore for CStore { fn allocator_kind(&self) -> Option { self.allocator_kind() } + + fn crate_extern_paths(&self, cnum: CrateNum) -> Vec { + self.get_crate_data(cnum).source().paths().cloned().collect() + } } diff --git a/src/librustc_middle/middle/cstore.rs b/src/librustc_middle/middle/cstore.rs index 97e877df96663..91754f458c891 100644 --- a/src/librustc_middle/middle/cstore.rs +++ b/src/librustc_middle/middle/cstore.rs @@ -203,6 +203,7 @@ pub trait CrateStore { fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; fn metadata_encoding_version(&self) -> &[u8]; fn allocator_kind(&self) -> Option; + fn crate_extern_paths(&self, cnum: CrateNum) -> Vec; } pub type CrateStoreDyn = dyn CrateStore + sync::Sync; diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index e2f601371b1ee..e6c0cd24bff4d 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -62,6 +62,7 @@ use std::hash::{Hash, Hasher}; use std::iter; use std::mem; use std::ops::{Bound, Deref}; +use std::path::PathBuf; use std::sync::Arc; type InternedSet<'tcx, T> = ShardedHashMap, ()>; @@ -1252,6 +1253,14 @@ impl<'tcx> TyCtxt<'tcx> { if cnum == LOCAL_CRATE { false } else { self.cstore.crate_is_private_dep_untracked(cnum) } } + pub fn crate_extern_paths(&self, cnum: CrateNum) -> Vec { + if cnum == LOCAL_CRATE { + self.sess.local_crate_source_file.iter().cloned().collect() + } else { + self.cstore.crate_extern_paths(cnum) + } + } + #[inline] pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash { if let Some(def_id) = def_id.as_local() { diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs index 0be37cb096038..d2635b8954502 100644 --- a/src/librustc_passes/lang_items.rs +++ b/src/librustc_passes/lang_items.rs @@ -146,6 +146,27 @@ impl LanguageItemCollector<'tcx> { )); } } + let mut note_def = |which, def_id: DefId| { + let location = if def_id.is_local() { + "the local crate".to_string() + } else { + let paths: Vec<_> = self + .tcx + .crate_extern_paths(def_id.krate) + .iter() + .map(|p| p.display().to_string()) + .collect(); + paths.join(", ") + }; + err.note(&format!( + "{} definition in `{}` loaded from {}", + which, + self.tcx.crate_name(def_id.krate), + location + )); + }; + note_def("first", original_def_id); + note_def("second", item_def_id); } err.emit(); } diff --git a/src/test/ui/duplicate_entry_error.rs b/src/test/ui/duplicate_entry_error.rs index b8d98a8999b9d..776ecedea7e7e 100644 --- a/src/test/ui/duplicate_entry_error.rs +++ b/src/test/ui/duplicate_entry_error.rs @@ -1,3 +1,4 @@ +// normalize-stderr-test "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib" // note-pattern: first defined in crate `std`. // Test for issue #31788 and E0152 diff --git a/src/test/ui/duplicate_entry_error.stderr b/src/test/ui/duplicate_entry_error.stderr index 2d52ea3f6c20e..93e4f9fa5e94b 100644 --- a/src/test/ui/duplicate_entry_error.stderr +++ b/src/test/ui/duplicate_entry_error.stderr @@ -1,5 +1,5 @@ error[E0152]: found duplicate lang item `panic_impl` - --> $DIR/duplicate_entry_error.rs:10:1 + --> $DIR/duplicate_entry_error.rs:11:1 | LL | / fn panic_impl(info: &PanicInfo) -> ! { LL | | @@ -8,6 +8,8 @@ LL | | } | |_^ | = note: the lang item is first defined in crate `std` (which `duplicate_entry_error` depends on) + = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib + = note: second definition in `duplicate_entry_error` loaded from the local crate error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0152.rs b/src/test/ui/error-codes/E0152.rs index 94467b9bddeb0..d716ca1a14fdf 100644 --- a/src/test/ui/error-codes/E0152.rs +++ b/src/test/ui/error-codes/E0152.rs @@ -1,3 +1,4 @@ +// normalize-stderr-test "loaded from .*liballoc-.*.rlib" -> "loaded from SYSROOT/liballoc-*.rlib" #![feature(lang_items)] #[lang = "owned_box"] diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr index fbaa276ce1093..5520b5454f9ed 100644 --- a/src/test/ui/error-codes/E0152.stderr +++ b/src/test/ui/error-codes/E0152.stderr @@ -1,10 +1,12 @@ error[E0152]: found duplicate lang item `owned_box` - --> $DIR/E0152.rs:4:1 + --> $DIR/E0152.rs:5:1 | LL | struct Foo; | ^^^^^^^^^^^ | = note: the lang item is first defined in crate `alloc` (which `std` depends on) + = note: first definition in `alloc` loaded from SYSROOT/liballoc-*.rlib + = note: second definition in `E0152` loaded from the local crate error: aborting due to previous error diff --git a/src/test/ui/panic-handler/panic-handler-std.rs b/src/test/ui/panic-handler/panic-handler-std.rs index 0acc2722cb21f..6183c886cfac7 100644 --- a/src/test/ui/panic-handler/panic-handler-std.rs +++ b/src/test/ui/panic-handler/panic-handler-std.rs @@ -1,3 +1,4 @@ +// normalize-stderr-test "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib" // error-pattern: found duplicate lang item `panic_impl` diff --git a/src/test/ui/panic-handler/panic-handler-std.stderr b/src/test/ui/panic-handler/panic-handler-std.stderr index f71c28e5aa641..1cba0ac3b9aaf 100644 --- a/src/test/ui/panic-handler/panic-handler-std.stderr +++ b/src/test/ui/panic-handler/panic-handler-std.stderr @@ -1,5 +1,5 @@ error[E0152]: found duplicate lang item `panic_impl` - --> $DIR/panic-handler-std.rs:7:1 + --> $DIR/panic-handler-std.rs:8:1 | LL | / fn panic(info: PanicInfo) -> ! { LL | | loop {} @@ -7,9 +7,11 @@ LL | | } | |_^ | = note: the lang item is first defined in crate `std` (which `panic_handler_std` depends on) + = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib + = note: second definition in `panic_handler_std` loaded from the local crate error: argument should be `&PanicInfo` - --> $DIR/panic-handler-std.rs:7:16 + --> $DIR/panic-handler-std.rs:8:16 | LL | fn panic(info: PanicInfo) -> ! { | ^^^^^^^^^ From b3652337a9539e703682a6babbf816192760bd3d Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 30 Jun 2020 17:18:13 +0200 Subject: [PATCH 63/92] Deny unsafe ops in unsafe fns, part 5 --- src/libcore/ffi.rs | 9 ++- src/libcore/slice/mod.rs | 144 +++++++++++++++++++++++++----------- src/libcore/slice/rotate.rs | 2 - 3 files changed, 108 insertions(+), 47 deletions(-) diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs index 7bc2866dc2e67..dda1d3467b66f 100644 --- a/src/libcore/ffi.rs +++ b/src/libcore/ffi.rs @@ -1,5 +1,6 @@ #![stable(feature = "", since = "1.30.0")] #![allow(non_camel_case_types)] +#![deny(unsafe_op_in_unsafe_fn)] //! Utilities related to FFI bindings. @@ -333,7 +334,8 @@ impl<'f> VaListImpl<'f> { /// Advance to the next arg. #[inline] pub unsafe fn arg(&mut self) -> T { - va_arg(self) + // SAFETY: the caller must uphold the safety contract for `va_arg`. + unsafe { va_arg(self) } } /// Copies the `va_list` at the current location. @@ -343,7 +345,10 @@ impl<'f> VaListImpl<'f> { { let mut ap = self.clone(); let ret = f(ap.as_va_list()); - va_end(&mut ap); + // SAFETY: the caller must uphold the safety contract for `va_end`. + unsafe { + va_end(&mut ap); + } ret } } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6a50cdbc1d9fb..ad9c43eccc12e 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -8,6 +8,7 @@ //! [`std::slice`]: ../../std/slice/index.html #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] // How this module is organized. // @@ -310,7 +311,8 @@ impl [T] { where I: SliceIndex, { - index.get_unchecked(self) + // SAFETY: the caller must uphold the safety requirements for `get_unchecked`. + unsafe { index.get_unchecked(self) } } /// Returns a mutable reference to an element or subslice, without doing @@ -341,7 +343,8 @@ impl [T] { where I: SliceIndex, { - index.get_unchecked_mut(self) + // SAFETY: the caller must uphold the safety requirements for `get_unchecked_mut`. + unsafe { index.get_unchecked_mut(self) } } /// Returns a raw pointer to the slice's buffer. @@ -2519,18 +2522,21 @@ impl [T] { // First, find at what point do we split between the first and 2nd slice. Easy with // ptr.align_offset. let ptr = self.as_ptr(); - let offset = crate::ptr::align_offset(ptr, mem::align_of::()); + let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::()) }; if offset > self.len() { (self, &[], &[]) } else { let (left, rest) = self.split_at(offset); - // now `rest` is definitely aligned, so `from_raw_parts_mut` below is okay let (us_len, ts_len) = rest.align_to_offsets::(); - ( - left, - from_raw_parts(rest.as_ptr() as *const U, us_len), - from_raw_parts(rest.as_ptr().add(rest.len() - ts_len), ts_len), - ) + // SAFETY: now `rest` is definitely aligned, so `from_raw_parts` below is okay, + // since the caller guarantees that we can transmute `T` to `U` safely. + unsafe { + ( + left, + from_raw_parts(rest.as_ptr() as *const U, us_len), + from_raw_parts(rest.as_ptr().add(rest.len() - ts_len), ts_len), + ) + } } } @@ -2575,21 +2581,23 @@ impl [T] { // First, find at what point do we split between the first and 2nd slice. Easy with // ptr.align_offset. let ptr = self.as_ptr(); - let offset = crate::ptr::align_offset(ptr, mem::align_of::()); + let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::()) }; if offset > self.len() { (self, &mut [], &mut []) } else { let (left, rest) = self.split_at_mut(offset); - // now `rest` is definitely aligned, so `from_raw_parts_mut` below is okay let (us_len, ts_len) = rest.align_to_offsets::(); let rest_len = rest.len(); let mut_ptr = rest.as_mut_ptr(); // We can't use `rest` again after this, that would invalidate its alias `mut_ptr`! - ( - left, - from_raw_parts_mut(mut_ptr as *mut U, us_len), - from_raw_parts_mut(mut_ptr.add(rest_len - ts_len), ts_len), - ) + // SAFETY: see comments for `align_to`. + unsafe { + ( + left, + from_raw_parts_mut(mut_ptr as *mut U, us_len), + from_raw_parts_mut(mut_ptr.add(rest_len - ts_len), ts_len), + ) + } } } @@ -2914,12 +2922,18 @@ impl SliceIndex<[T]> for usize { #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &T { - &*slice.as_ptr().add(self) + // SAFETY: `slice` cannot be longer than `isize::MAX` and + // the caller guarantees that `self` is in bounds of `slice` + // so `self` cannot overflow an `isize`, so the call to `add` is safe. + // The obtained pointer comes from a reference which is guaranteed + // to be valid. + unsafe { &*slice.as_ptr().add(self) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut T { - &mut *slice.as_mut_ptr().add(self) + // SAFETY: see comments for `get_unchecked` above. + unsafe { &mut *slice.as_mut_ptr().add(self) } } #[inline] @@ -2959,12 +2973,18 @@ impl SliceIndex<[T]> for ops::Range { #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) + // SAFETY: `slice` cannot be longer than `isize::MAX` and + // the caller guarantees that `self` is in bounds of `slice` + // so `self` cannot overflow an `isize`, so the call to `add` is safe. + // Also, since the caller guarantees that `self` is in bounds of `slice`, + // `from_raw_parts` will give a subslice of `slice` which is always safe. + unsafe { from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { - from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) + // SAFETY: see comments for `get_unchecked` above. + unsafe { from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) } } #[inline] @@ -3004,12 +3024,14 @@ impl SliceIndex<[T]> for ops::RangeTo { #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - (0..self.end).get_unchecked(slice) + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..self.end).get_unchecked(slice) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { - (0..self.end).get_unchecked_mut(slice) + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..self.end).get_unchecked_mut(slice) } } #[inline] @@ -3039,12 +3061,14 @@ impl SliceIndex<[T]> for ops::RangeFrom { #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - (self.start..slice.len()).get_unchecked(slice) + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (self.start..slice.len()).get_unchecked(slice) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { - (self.start..slice.len()).get_unchecked_mut(slice) + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } } #[inline] @@ -3113,12 +3137,14 @@ impl SliceIndex<[T]> for ops::RangeInclusive { #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - (*self.start()..self.end() + 1).get_unchecked(slice) + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { - (*self.start()..self.end() + 1).get_unchecked_mut(slice) + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } } #[inline] @@ -3154,12 +3180,14 @@ impl SliceIndex<[T]> for ops::RangeToInclusive { #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - (0..=self.end).get_unchecked(slice) + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..=self.end).get_unchecked(slice) } } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { - (0..=self.end).get_unchecked_mut(slice) + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..=self.end).get_unchecked_mut(slice) } } #[inline] @@ -3308,7 +3336,9 @@ macro_rules! iterator { self.ptr.as_ptr() } else { let old = self.ptr.as_ptr(); - self.ptr = NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)); + // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, + // so this new pointer is inside `self` and thus guaranteed to be non-null. + self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; old } } @@ -3322,7 +3352,10 @@ macro_rules! iterator { zst_shrink!(self, offset); self.ptr.as_ptr() } else { - self.end = self.end.offset(-offset); + // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, + // which is guaranteed to not overflow an `isize`. Also, the resulting pointer + // is in bounds of `slice`, which fulfills the other requirements for `offset`. + self.end = unsafe { self.end.offset(-offset) }; self.end } } @@ -4640,7 +4673,11 @@ impl FusedIterator for Windows<'_, T> {} #[doc(hidden)] unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { - from_raw_parts(self.v.as_ptr().add(i), self.size) + // SAFETY: since the caller guarantees that `i` is in bounds, + // which means that `i` cannot overflow an `isize`, and the + // slice created by `from_raw_parts` is a subslice of `self.v` + // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(i), self.size) } } fn may_have_side_effect() -> bool { false @@ -4784,7 +4821,14 @@ unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { None => self.v.len(), Some(end) => cmp::min(end, self.v.len()), }; - from_raw_parts(self.v.as_ptr().add(start), end - start) + // SAFETY: the caller guarantees that `i` is in bounds, + // which means that `start` must be in bounds of the + // underlying `self.v` slice, and we made sure that `end` + // is also in bounds of `self.v`. Thus, `start` cannot overflow + // an `isize`, and the slice constructed by `from_raw_parts` + // is a subslice of `self.v` which is guaranteed to be valid + // for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } } fn may_have_side_effect() -> bool { false @@ -4926,7 +4970,8 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { None => self.v.len(), Some(end) => cmp::min(end, self.v.len()), }; - from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) + // SAFETY: see comments for `Chunks::get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } } fn may_have_side_effect() -> bool { false @@ -5063,7 +5108,8 @@ impl FusedIterator for ChunksExact<'_, T> {} unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let start = i * self.chunk_size; - from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) + // SAFETY: mostly identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } } fn may_have_side_effect() -> bool { false @@ -5197,7 +5243,8 @@ impl FusedIterator for ChunksExactMut<'_, T> {} unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let start = i * self.chunk_size; - from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) + // SAFETY: see comments for `ChunksExactMut::get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } } fn may_have_side_effect() -> bool { false @@ -5344,7 +5391,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { None => 0, Some(start) => start, }; - from_raw_parts(self.v.as_ptr().add(start), end - start) + // SAFETY: mostly identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } } fn may_have_side_effect() -> bool { false @@ -5489,7 +5537,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { None => 0, Some(start) => start, }; - from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) + // SAFETY: see comments for `RChunks::get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } } fn may_have_side_effect() -> bool { false @@ -5630,7 +5679,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T] { let end = self.v.len() - i * self.chunk_size; let start = end - self.chunk_size; - from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) + // SAFETY: mostmy identical to `Chunks::get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } } fn may_have_side_effect() -> bool { false @@ -5769,7 +5819,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T] { let end = self.v.len() - i * self.chunk_size; let start = end - self.chunk_size; - from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) + // SAFETY: see comments for `RChunksExact::get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } } fn may_have_side_effect() -> bool { false @@ -5865,7 +5916,8 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { mem::size_of::().saturating_mul(len) <= isize::MAX as usize, "attempt to create slice covering at least half the address space" ); - &*ptr::slice_from_raw_parts(data, len) + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::slice_from_raw_parts(data, len) } } /// Performs the same functionality as [`from_raw_parts`], except that a @@ -5905,7 +5957,8 @@ pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] mem::size_of::().saturating_mul(len) <= isize::MAX as usize, "attempt to create slice covering at least half the address space" ); - &mut *ptr::slice_from_raw_parts_mut(data, len) + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } } /// Converts a reference to T into a slice of length 1 (without copying). @@ -6181,7 +6234,11 @@ impl_marker_for!(BytewiseEquality, #[doc(hidden)] unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a T { - &*self.ptr.as_ptr().add(i) + // SAFETY: the caller must guarantee that `i` is in bounds + // of the underlying slice, so `i` cannot overflow an `isize`, + // and the returned references is guaranteed to refer to an element + // of the slice and thus guaranteed to be valid. + unsafe { &*self.ptr.as_ptr().add(i) } } fn may_have_side_effect() -> bool { false @@ -6191,7 +6248,8 @@ unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { #[doc(hidden)] unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T { - &mut *self.ptr.as_ptr().add(i) + // SAFETY: see comments for `Iter::get_unchecked`. + unsafe { &mut *self.ptr.as_ptr().add(i) } } fn may_have_side_effect() -> bool { false diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index 7bdd7d009e156..a89596b15ef94 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -1,7 +1,5 @@ // ignore-tidy-undocumented-unsafe -#![deny(unsafe_op_in_unsafe_fn)] - use crate::cmp; use crate::mem::{self, MaybeUninit}; use crate::ptr; From 1b3ef660261c880783db0154b89c09a1c4608845 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 27 Jun 2020 14:54:19 -0700 Subject: [PATCH 64/92] Switch crate_extern_paths to a query, and tweak wording. --- .../rmeta/decoder/cstore_impl.rs | 7 ++----- src/librustc_middle/middle/cstore.rs | 1 - src/librustc_middle/query/mod.rs | 4 ++++ src/librustc_middle/ty/context.rs | 9 --------- src/librustc_middle/ty/query/mod.rs | 1 + src/librustc_passes/lang_items.rs | 19 ++++++++++--------- src/test/ui/duplicate_entry_error.stderr | 2 +- src/test/ui/error-codes/E0152.stderr | 2 +- .../ui/panic-handler/panic-handler-std.stderr | 2 +- 9 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index 3472d8987c65c..abbe45fe02e25 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -27,7 +27,6 @@ use rustc_span::symbol::{Ident, Symbol}; use rustc_data_structures::sync::Lrc; use smallvec::SmallVec; use std::any::Any; -use std::path::PathBuf; macro_rules! provide { (<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident, @@ -240,6 +239,8 @@ provide! { <'tcx> tcx, def_id, other, cdata, syms } + + crate_extern_paths => { cdata.source().paths().cloned().collect() } } pub fn provide(providers: &mut Providers<'_>) { @@ -514,8 +515,4 @@ impl CrateStore for CStore { fn allocator_kind(&self) -> Option { self.allocator_kind() } - - fn crate_extern_paths(&self, cnum: CrateNum) -> Vec { - self.get_crate_data(cnum).source().paths().cloned().collect() - } } diff --git a/src/librustc_middle/middle/cstore.rs b/src/librustc_middle/middle/cstore.rs index 91754f458c891..97e877df96663 100644 --- a/src/librustc_middle/middle/cstore.rs +++ b/src/librustc_middle/middle/cstore.rs @@ -203,7 +203,6 @@ pub trait CrateStore { fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; fn metadata_encoding_version(&self) -> &[u8]; fn allocator_kind(&self) -> Option; - fn crate_extern_paths(&self, cnum: CrateNum) -> Vec; } pub type CrateStoreDyn = dyn CrateStore + sync::Sync; diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index ba5a8c3ec2052..e7f9ad9d1cfd7 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1042,6 +1042,10 @@ rustc_queries! { eval_always desc { "looking up the extra filename for a crate" } } + query crate_extern_paths(_: CrateNum) -> Vec { + eval_always + desc { "looking up the paths for extern crates" } + } } TypeChecking { diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index e6c0cd24bff4d..e2f601371b1ee 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -62,7 +62,6 @@ use std::hash::{Hash, Hasher}; use std::iter; use std::mem; use std::ops::{Bound, Deref}; -use std::path::PathBuf; use std::sync::Arc; type InternedSet<'tcx, T> = ShardedHashMap, ()>; @@ -1253,14 +1252,6 @@ impl<'tcx> TyCtxt<'tcx> { if cnum == LOCAL_CRATE { false } else { self.cstore.crate_is_private_dep_untracked(cnum) } } - pub fn crate_extern_paths(&self, cnum: CrateNum) -> Vec { - if cnum == LOCAL_CRATE { - self.sess.local_crate_source_file.iter().cloned().collect() - } else { - self.cstore.crate_extern_paths(cnum) - } - } - #[inline] pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash { if let Some(def_id) = def_id.as_local() { diff --git a/src/librustc_middle/ty/query/mod.rs b/src/librustc_middle/ty/query/mod.rs index 35d19b7603faf..2ad49b1acce43 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/src/librustc_middle/ty/query/mod.rs @@ -57,6 +57,7 @@ use rustc_span::{Span, DUMMY_SP}; use std::borrow::Cow; use std::collections::BTreeMap; use std::ops::Deref; +use std::path::PathBuf; use std::sync::Arc; #[macro_use] diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs index d2635b8954502..0326591a931f5 100644 --- a/src/librustc_passes/lang_items.rs +++ b/src/librustc_passes/lang_items.rs @@ -147,8 +147,9 @@ impl LanguageItemCollector<'tcx> { } } let mut note_def = |which, def_id: DefId| { - let location = if def_id.is_local() { - "the local crate".to_string() + let crate_name = self.tcx.crate_name(def_id.krate); + let note = if def_id.is_local() { + format!("{} definition in the local crate (`{}`)", which, crate_name) } else { let paths: Vec<_> = self .tcx @@ -156,14 +157,14 @@ impl LanguageItemCollector<'tcx> { .iter() .map(|p| p.display().to_string()) .collect(); - paths.join(", ") + format!( + "{} definition in `{}` loaded from {}", + which, + crate_name, + paths.join(", ") + ) }; - err.note(&format!( - "{} definition in `{}` loaded from {}", - which, - self.tcx.crate_name(def_id.krate), - location - )); + err.note(¬e); }; note_def("first", original_def_id); note_def("second", item_def_id); diff --git a/src/test/ui/duplicate_entry_error.stderr b/src/test/ui/duplicate_entry_error.stderr index 93e4f9fa5e94b..61cccf40ed8a5 100644 --- a/src/test/ui/duplicate_entry_error.stderr +++ b/src/test/ui/duplicate_entry_error.stderr @@ -9,7 +9,7 @@ LL | | } | = note: the lang item is first defined in crate `std` (which `duplicate_entry_error` depends on) = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib - = note: second definition in `duplicate_entry_error` loaded from the local crate + = note: second definition in the local crate (`duplicate_entry_error`) error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0152.stderr b/src/test/ui/error-codes/E0152.stderr index 5520b5454f9ed..7445c2880af1c 100644 --- a/src/test/ui/error-codes/E0152.stderr +++ b/src/test/ui/error-codes/E0152.stderr @@ -6,7 +6,7 @@ LL | struct Foo; | = note: the lang item is first defined in crate `alloc` (which `std` depends on) = note: first definition in `alloc` loaded from SYSROOT/liballoc-*.rlib - = note: second definition in `E0152` loaded from the local crate + = note: second definition in the local crate (`E0152`) error: aborting due to previous error diff --git a/src/test/ui/panic-handler/panic-handler-std.stderr b/src/test/ui/panic-handler/panic-handler-std.stderr index 1cba0ac3b9aaf..bb656089bcaff 100644 --- a/src/test/ui/panic-handler/panic-handler-std.stderr +++ b/src/test/ui/panic-handler/panic-handler-std.stderr @@ -8,7 +8,7 @@ LL | | } | = note: the lang item is first defined in crate `std` (which `panic_handler_std` depends on) = note: first definition in `std` loaded from SYSROOT/libstd-*.rlib - = note: second definition in `panic_handler_std` loaded from the local crate + = note: second definition in the local crate (`panic_handler_std`) error: argument should be `&PanicInfo` --> $DIR/panic-handler-std.rs:8:16 From a1623ff3b6a48e7ac29e1c25900989851278743b Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 30 Jun 2020 19:10:22 +0200 Subject: [PATCH 65/92] Deny unsafe ops in unsafe fns, part 6 And final part!!! --- src/libcore/alloc/mod.rs | 1 - src/libcore/cell.rs | 1 - src/libcore/char/convert.rs | 2 - src/libcore/char/methods.rs | 2 - src/libcore/convert/num.rs | 2 - src/libcore/ffi.rs | 1 - src/libcore/future/mod.rs | 4 +- src/libcore/hash/sip.rs | 1 - src/libcore/hint.rs | 2 - src/libcore/intrinsics.rs | 1 - src/libcore/iter/mod.rs | 1 - src/libcore/lib.rs | 9 ++- src/libcore/mem/mod.rs | 1 - src/libcore/num/f32.rs | 1 - src/libcore/num/f64.rs | 1 - src/libcore/num/mod.rs | 1 - src/libcore/pin.rs | 1 - src/libcore/ptr/const_ptr.rs | 31 ++++++--- src/libcore/ptr/mod.rs | 126 ++++++++++++++++++++++++++--------- src/libcore/ptr/mut_ptr.rs | 64 ++++++++++++------ src/libcore/ptr/non_null.rs | 11 ++- src/libcore/ptr/unique.rs | 11 ++- src/libcore/slice/mod.rs | 1 - src/libcore/str/mod.rs | 1 - src/libcore/sync/atomic.rs | 1 - 25 files changed, 185 insertions(+), 93 deletions(-) diff --git a/src/libcore/alloc/mod.rs b/src/libcore/alloc/mod.rs index d00dbd2c34d56..be4e051b1ca42 100644 --- a/src/libcore/alloc/mod.rs +++ b/src/libcore/alloc/mod.rs @@ -1,7 +1,6 @@ //! Memory allocation APIs #![stable(feature = "alloc_module", since = "1.28.0")] -#![deny(unsafe_op_in_unsafe_fn)] mod global; mod layout; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index caaf940b62cb2..51d9695687f4a 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -187,7 +187,6 @@ //! #![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 001362ba1c375..c329eec76ac3d 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -1,7 +1,5 @@ //! Character conversions. -#![deny(unsafe_op_in_unsafe_fn)] - use crate::convert::TryFrom; use crate::fmt; use crate::mem::transmute; diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 5a62c92694fad..72555d781ed38 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -1,7 +1,5 @@ //! impl char {} -#![deny(unsafe_op_in_unsafe_fn)] - use crate::slice; use crate::str::from_utf8_unchecked_mut; use crate::unicode::printable::is_printable; diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs index 094618acc5885..336c0b26bc7d7 100644 --- a/src/libcore/convert/num.rs +++ b/src/libcore/convert/num.rs @@ -1,5 +1,3 @@ -#![deny(unsafe_op_in_unsafe_fn)] - use super::{From, TryFrom}; use crate::num::TryFromIntError; diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs index dda1d3467b66f..ca4632006509f 100644 --- a/src/libcore/ffi.rs +++ b/src/libcore/ffi.rs @@ -1,6 +1,5 @@ #![stable(feature = "", since = "1.30.0")] #![allow(non_camel_case_types)] -#![deny(unsafe_op_in_unsafe_fn)] //! Utilities related to FFI bindings. diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 9dbc23f5c04c5..2555d91ae8d9a 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -85,5 +85,7 @@ where #[unstable(feature = "gen_future", issue = "50547")] #[inline] pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> { - &mut *cx.0.as_ptr().cast() + // SAFETY: the caller must guarantee that `cx.0` is a valid pointer + // that fulfills all the requirements for a mutable reference. + unsafe { &mut *cx.0.as_ptr().cast() } } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 84148058d03f7..f2bbf646f3272 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -1,7 +1,6 @@ //! An implementation of SipHash. #![allow(deprecated)] // the types in this module are deprecated -#![deny(unsafe_op_in_unsafe_fn)] use crate::cmp; use crate::marker::PhantomData; diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index fd2d443dde8d8..9ebcde79b633d 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -2,8 +2,6 @@ //! Hints to compiler that affects how code should be emitted or optimized. -#![deny(unsafe_op_in_unsafe_fn)] - use crate::intrinsics; /// Informs the compiler that this point in the code is not reachable, enabling diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 237c6e0545f8f..3c0d5f8bfe7be 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -53,7 +53,6 @@ issue = "none" )] #![allow(missing_docs)] -#![deny(unsafe_op_in_unsafe_fn)] use crate::marker::DiscriminantKind; use crate::mem; diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 4a1f6418bb5b3..080b70c6368b2 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -309,7 +309,6 @@ //! [`min`]: trait.Iterator.html#method.min #![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] use crate::ops::Try; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1459a6b2f16f7..81c2344e205c5 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -149,6 +149,7 @@ #![feature(const_caller_location)] #![feature(no_niche)] // rust-lang/rust#68303 #![feature(unsafe_block_in_unsafe_fn)] +#![deny(unsafe_op_in_unsafe_fn)] #[prelude_import] #[allow(unused)] @@ -279,7 +280,13 @@ pub mod primitive; // set up in such a way that directly pulling it here works such that the // crate uses the this crate as its libcore. #[path = "../stdarch/crates/core_arch/src/mod.rs"] -#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)] +#[allow( + missing_docs, + missing_debug_implementations, + dead_code, + unused_imports, + unsafe_op_in_unsafe_fn +)] // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. #[cfg_attr(not(bootstrap), allow(clashing_extern_declarations))] diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs index 20ea83fd063c6..272088815ece9 100644 --- a/src/libcore/mem/mod.rs +++ b/src/libcore/mem/mod.rs @@ -4,7 +4,6 @@ //! types, initializing and manipulating memory. #![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] use crate::clone; use crate::cmp; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 028beb86e68ba..061d1ea6b1c46 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -9,7 +9,6 @@ //! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] use crate::convert::FloatToInt; #[cfg(not(test))] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 74e38c128b377..b0df4d64f6ee1 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -9,7 +9,6 @@ //! new code should use the associated constants directly on the primitive type. #![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] use crate::convert::FloatToInt; #[cfg(not(test))] diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 918eea7acb3ad..2ded2e9c086c8 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -3,7 +3,6 @@ //! Numeric traits and functions for the built-in numeric types. #![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] use crate::convert::Infallible; use crate::fmt; diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index b042bed681e38..da299f026f8f1 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -375,7 +375,6 @@ //! [`i32`]: ../../std/primitive.i32.html #![stable(feature = "pin", since = "1.33.0")] -#![deny(unsafe_op_in_unsafe_fn)] use crate::cmp::{self, PartialEq, PartialOrd}; use crate::fmt; diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index 64a506a6377f2..d1d7a71523822 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -95,7 +95,9 @@ impl *const T { #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { - if self.is_null() { None } else { Some(&*self) } + // SAFETY: the caller must guarantee that `self` is valid + // for a reference if it isn't null. + if self.is_null() { None } else { unsafe { Some(&*self) } } } /// Calculates the offset from a pointer. @@ -157,7 +159,8 @@ impl *const T { where T: Sized, { - intrinsics::offset(self, count) + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { intrinsics::offset(self, count) } } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -292,7 +295,8 @@ impl *const T { { let pointee_size = mem::size_of::(); assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); - intrinsics::ptr_offset_from(self, origin) + // SAFETY: the caller must uphold the safety contract for `ptr_offset_from`. + unsafe { intrinsics::ptr_offset_from(self, origin) } } /// Returns whether two pointers are guaranteed to be equal. @@ -471,7 +475,8 @@ impl *const T { where T: Sized, { - self.offset(count as isize) + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { self.offset(count as isize) } } /// Calculates the offset from a pointer (convenience for @@ -534,7 +539,8 @@ impl *const T { where T: Sized, { - self.offset((count as isize).wrapping_neg()) + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { self.offset((count as isize).wrapping_neg()) } } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -663,7 +669,8 @@ impl *const T { where T: Sized, { - read(self) + // SAFETY: the caller must uphold the safety contract for `read`. + unsafe { read(self) } } /// Performs a volatile read of the value from `self` without moving it. This @@ -682,7 +689,8 @@ impl *const T { where T: Sized, { - read_volatile(self) + // SAFETY: the caller must uphold the safety contract for `read_volatile`. + unsafe { read_volatile(self) } } /// Reads the value from `self` without moving it. This leaves the @@ -699,7 +707,8 @@ impl *const T { where T: Sized, { - read_unaligned(self) + // SAFETY: the caller must uphold the safety contract for `read_unaligned`. + unsafe { read_unaligned(self) } } /// Copies `count * size_of` bytes from `self` to `dest`. The source @@ -716,7 +725,8 @@ impl *const T { where T: Sized, { - copy(self, dest, count) + // SAFETY: the caller must uphold the safety contract for `copy`. + unsafe { copy(self, dest, count) } } /// Copies `count * size_of` bytes from `self` to `dest`. The source @@ -733,7 +743,8 @@ impl *const T { where T: Sized, { - copy_nonoverlapping(self, dest, count) + // SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`. + unsafe { copy_nonoverlapping(self, dest, count) } } /// Computes the offset that needs to be applied to the pointer in order to make it aligned to diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs index ca2b0c85ec121..5f028f9ea76ca 100644 --- a/src/libcore/ptr/mod.rs +++ b/src/libcore/ptr/mod.rs @@ -184,7 +184,9 @@ mod mut_ptr; pub unsafe fn drop_in_place(to_drop: *mut T) { // Code here does not matter - this is replaced by the // real drop glue by the compiler. - drop_in_place(to_drop) + + // SAFETY: see comment above + unsafe { drop_in_place(to_drop) } } /// Creates a null raw pointer. @@ -374,9 +376,15 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { let mut tmp = MaybeUninit::::uninit(); // Perform the swap - copy_nonoverlapping(x, tmp.as_mut_ptr(), 1); - copy(y, x, 1); // `x` and `y` may overlap - copy_nonoverlapping(tmp.as_ptr(), y, 1); + // SAFETY: the caller must guarantee that `x` and `y` are + // valid for writes and properly aligned. `tmp` cannot be + // overlapping either `x` or `y` because `tmp` was just allocated + // on the stack as a separate allocated object. + unsafe { + copy_nonoverlapping(x, tmp.as_mut_ptr(), 1); + copy(y, x, 1); // `x` and `y` may overlap + copy_nonoverlapping(tmp.as_ptr(), y, 1); + } } /// Swaps `count * size_of::()` bytes between the two regions of memory @@ -432,7 +440,9 @@ pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; let len = mem::size_of::() * count; - swap_nonoverlapping_bytes(x, y, len) + // SAFETY: the caller must guarantee that `x` and `y` are + // valid for writes and properly aligned. + unsafe { swap_nonoverlapping_bytes(x, y, len) } } #[inline] @@ -440,11 +450,16 @@ pub(crate) unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { // For types smaller than the block optimization below, // just swap directly to avoid pessimizing codegen. if mem::size_of::() < 32 { - let z = read(x); - copy_nonoverlapping(y, x, 1); - write(y, z); + // SAFETY: the caller must guarantee that `x` and `y` are valid + // for writes, properly aligned, and non-overlapping. + unsafe { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); + } } else { - swap_nonoverlapping(x, y, 1); + // SAFETY: the caller must uphold the safety contract for `swap_nonoverlapping`. + unsafe { swap_nonoverlapping(x, y, 1) }; } } @@ -471,14 +486,23 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { // Declaring `t` here avoids aligning the stack when this loop is unused let mut t = mem::MaybeUninit::::uninit(); let t = t.as_mut_ptr() as *mut u8; - let x = x.add(i); - let y = y.add(i); - // Swap a block of bytes of x & y, using t as a temporary buffer - // This should be optimized into efficient SIMD operations where available - copy_nonoverlapping(x, t, block_size); - copy_nonoverlapping(y, x, block_size); - copy_nonoverlapping(t, y, block_size); + // SAFETY: As `i < len`, and as the caller must guarantee that `x` and `y` are valid + // for `len` bytes, `x + i` and `y + i` must be valid adresses, which fulfills the + // safety contract for `add`. + // + // Also, the caller must guarantee that `x` and `y` are valid for writes, properly aligned, + // and non-overlapping, which fulfills the safety contract for `copy_nonoverlapping`. + unsafe { + let x = x.add(i); + let y = y.add(i); + + // Swap a block of bytes of x & y, using t as a temporary buffer + // This should be optimized into efficient SIMD operations where available + copy_nonoverlapping(x, t, block_size); + copy_nonoverlapping(y, x, block_size); + copy_nonoverlapping(t, y, block_size); + } i += block_size; } @@ -488,12 +512,16 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { let rem = len - i; let t = t.as_mut_ptr() as *mut u8; - let x = x.add(i); - let y = y.add(i); - copy_nonoverlapping(x, t, rem); - copy_nonoverlapping(y, x, rem); - copy_nonoverlapping(t, y, rem); + // SAFETY: see previous safety comment. + unsafe { + let x = x.add(i); + let y = y.add(i); + + copy_nonoverlapping(x, t, rem); + copy_nonoverlapping(y, x, rem); + copy_nonoverlapping(t, y, rem); + } } } @@ -540,7 +568,13 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn replace(dst: *mut T, mut src: T) -> T { - mem::swap(&mut *dst, &mut src); // cannot overlap + // SAFETY: the caller must guarantee that `dst` is valid to be + // cast to a mutable reference (valid for writes, aligned, initialized), + // and cannot overlap `src` since `dst` must point to a distinct + // allocated object. + unsafe { + mem::swap(&mut *dst, &mut src); // cannot overlap + } src } @@ -658,8 +692,16 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { pub unsafe fn read(src: *const T) -> T { // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); - copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - tmp.assume_init() + // SAFETY: the caller must guarantee that `src` is valid for reads. + // `src` cannot overlap `tmp` because `tmp` was just allocated on + // the stack as a separate allocated object. + // + // Also, since we just wrote a valid value into `tmp`, it is guaranteed + // to be properly initialized. + unsafe { + copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + tmp.assume_init() + } } /// Reads the value from `src` without moving it. This leaves the @@ -752,8 +794,16 @@ pub unsafe fn read(src: *const T) -> T { pub unsafe fn read_unaligned(src: *const T) -> T { // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); - copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); - tmp.assume_init() + // SAFETY: the caller must guarantee that `src` is valid for reads. + // `src` cannot overlap `tmp` because `tmp` was just allocated on + // the stack as a separate allocated object. + // + // Also, since we just wrote a valid value into `tmp`, it is guaranteed + // to be properly initialized. + unsafe { + copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); + tmp.assume_init() + } } /// Overwrites a memory location with the given value without reading or @@ -847,7 +897,8 @@ pub unsafe fn write(dst: *mut T, src: T) { // Not panicking to keep codegen impact smaller. abort(); } - intrinsics::move_val_init(&mut *dst, src) + // SAFETY: the caller must uphold the safety contract for `move_val_init`. + unsafe { intrinsics::move_val_init(&mut *dst, src) } } /// Overwrites a memory location with the given value without reading or @@ -939,8 +990,13 @@ pub unsafe fn write(dst: *mut T, src: T) { #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] pub unsafe fn write_unaligned(dst: *mut T, src: T) { - // `copy_nonoverlapping` takes care of debug_assert. - copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::()); + // SAFETY: the caller must guarantee that `dst` is valid for writes. + // `dst` cannot overlap `src` because the caller has mutable access + // to `dst` while `src` is owned by this function. + unsafe { + // `copy_nonoverlapping` takes care of debug_assert. + copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::()); + } mem::forget(src); } @@ -1015,7 +1071,8 @@ pub unsafe fn read_volatile(src: *const T) -> T { // Not panicking to keep codegen impact smaller. abort(); } - intrinsics::volatile_load(src) + // SAFETY: the caller must uphold the safety contract for `volatile_load`. + unsafe { intrinsics::volatile_load(src) } } /// Performs a volatile write of a memory location with the given value without @@ -1087,7 +1144,10 @@ pub unsafe fn write_volatile(dst: *mut T, src: T) { // Not panicking to keep codegen impact smaller. abort(); } - intrinsics::volatile_store(dst, src); + // SAFETY: the caller must uphold the safety contract for `volatile_store`. + unsafe { + intrinsics::volatile_store(dst, src); + } } /// Align pointer `p`. @@ -1173,8 +1233,8 @@ pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { } let smoda = stride & a_minus_one; - // a is power-of-two so cannot be 0. stride = 0 is handled above. - let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); + // SAFETY: a is power-of-two so cannot be 0. stride = 0 is handled above. + let gcdpow = unsafe { intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)) }; let gcd = 1usize << gcdpow; if p as usize & (gcd.wrapping_sub(1)) == 0 { diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 6b5cd9fdb854d..7d4b6339b511f 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -89,7 +89,9 @@ impl *mut T { #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] pub unsafe fn as_ref<'a>(self) -> Option<&'a T> { - if self.is_null() { None } else { Some(&*self) } + // SAFETY: the caller must guarantee that `self` is valid for a + // reference if it isn't null. + if self.is_null() { None } else { unsafe { Some(&*self) } } } /// Calculates the offset from a pointer. @@ -151,7 +153,10 @@ impl *mut T { where T: Sized, { - intrinsics::offset(self, count) as *mut T + // SAFETY: the caller must uphold the safety contract for `offset`. + // The obtained pointer is valid for writes since the caller must + // guarantee that it points to the same allocated object as `self`. + unsafe { intrinsics::offset(self, count) as *mut T } } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -270,7 +275,9 @@ impl *mut T { #[stable(feature = "ptr_as_ref", since = "1.9.0")] #[inline] pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> { - if self.is_null() { None } else { Some(&mut *self) } + // SAFETY: the caller must guarantee that `self` is be valid for + // a mutable reference if it isn't null. + if self.is_null() { None } else { unsafe { Some(&mut *self) } } } /// Returns whether two pointers are guaranteed to be equal. @@ -406,7 +413,8 @@ impl *mut T { where T: Sized, { - (self as *const T).offset_from(origin) + // SAFETY: the caller must uphold the safety contract for `offset_from`. + unsafe { (self as *const T).offset_from(origin) } } /// Calculates the distance between two pointers. The returned value is in @@ -518,7 +526,8 @@ impl *mut T { where T: Sized, { - self.offset(count as isize) + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { self.offset(count as isize) } } /// Calculates the offset from a pointer (convenience for @@ -581,7 +590,8 @@ impl *mut T { where T: Sized, { - self.offset((count as isize).wrapping_neg()) + // SAFETY: the caller must uphold the safety contract for `offset`. + unsafe { self.offset((count as isize).wrapping_neg()) } } /// Calculates the offset from a pointer using wrapping arithmetic. @@ -710,7 +720,8 @@ impl *mut T { where T: Sized, { - read(self) + // SAFETY: the caller must uphold the safety contract for ``. + unsafe { read(self) } } /// Performs a volatile read of the value from `self` without moving it. This @@ -729,7 +740,8 @@ impl *mut T { where T: Sized, { - read_volatile(self) + // SAFETY: the caller must uphold the safety contract for `read_volatile`. + unsafe { read_volatile(self) } } /// Reads the value from `self` without moving it. This leaves the @@ -746,7 +758,8 @@ impl *mut T { where T: Sized, { - read_unaligned(self) + // SAFETY: the caller must uphold the safety contract for `read_unaligned`. + unsafe { read_unaligned(self) } } /// Copies `count * size_of` bytes from `self` to `dest`. The source @@ -763,7 +776,8 @@ impl *mut T { where T: Sized, { - copy(self, dest, count) + // SAFETY: the caller must uphold the safety contract for `copy`. + unsafe { copy(self, dest, count) } } /// Copies `count * size_of` bytes from `self` to `dest`. The source @@ -780,7 +794,8 @@ impl *mut T { where T: Sized, { - copy_nonoverlapping(self, dest, count) + // SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`. + unsafe { copy_nonoverlapping(self, dest, count) } } /// Copies `count * size_of` bytes from `src` to `self`. The source @@ -797,7 +812,8 @@ impl *mut T { where T: Sized, { - copy(src, self, count) + // SAFETY: the caller must uphold the safety contract for `copy`. + unsafe { copy(src, self, count) } } /// Copies `count * size_of` bytes from `src` to `self`. The source @@ -814,7 +830,8 @@ impl *mut T { where T: Sized, { - copy_nonoverlapping(src, self, count) + // SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`. + unsafe { copy_nonoverlapping(src, self, count) } } /// Executes the destructor (if any) of the pointed-to value. @@ -825,7 +842,8 @@ impl *mut T { #[stable(feature = "pointer_methods", since = "1.26.0")] #[inline] pub unsafe fn drop_in_place(self) { - drop_in_place(self) + // SAFETY: the caller must uphold the safety contract for `drop_in_place`. + unsafe { drop_in_place(self) } } /// Overwrites a memory location with the given value without reading or @@ -840,7 +858,8 @@ impl *mut T { where T: Sized, { - write(self, val) + // SAFETY: the caller must uphold the safety contract for `write`. + unsafe { write(self, val) } } /// Invokes memset on the specified pointer, setting `count * size_of::()` @@ -855,7 +874,8 @@ impl *mut T { where T: Sized, { - write_bytes(self, val, count) + // SAFETY: the caller must uphold the safety contract for `write_bytes`. + unsafe { write_bytes(self, val, count) } } /// Performs a volatile write of a memory location with the given value without @@ -874,7 +894,8 @@ impl *mut T { where T: Sized, { - write_volatile(self, val) + // SAFETY: the caller must uphold the safety contract for `write_volatile`. + unsafe { write_volatile(self, val) } } /// Overwrites a memory location with the given value without reading or @@ -891,7 +912,8 @@ impl *mut T { where T: Sized, { - write_unaligned(self, val) + // SAFETY: the caller must uphold the safety contract for `write_unaligned`. + unsafe { write_unaligned(self, val) } } /// Replaces the value at `self` with `src`, returning the old @@ -906,7 +928,8 @@ impl *mut T { where T: Sized, { - replace(self, src) + // SAFETY: the caller must uphold the safety contract for `replace`. + unsafe { replace(self, src) } } /// Swaps the values at two mutable locations of the same type, without @@ -922,7 +945,8 @@ impl *mut T { where T: Sized, { - swap(self, with) + // SAFETY: the caller must uphold the safety contract for `swap`. + unsafe { swap(self, with) } } /// Computes the offset that needs to be applied to the pointer in order to make it aligned to diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs index 870364a61dd47..c2d31bfb6a4ee 100644 --- a/src/libcore/ptr/non_null.rs +++ b/src/libcore/ptr/non_null.rs @@ -87,7 +87,8 @@ impl NonNull { #[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.32.0")] #[inline] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - NonNull { pointer: ptr as _ } + // SAFETY: the caller must guarantee that `ptr` is non-null. + unsafe { NonNull { pointer: ptr as _ } } } /// Creates a new `NonNull` if `ptr` is non-null. @@ -118,7 +119,9 @@ impl NonNull { #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub unsafe fn as_ref(&self) -> &T { - &*self.as_ptr() + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a reference. + unsafe { &*self.as_ptr() } } /// Mutably dereferences the content. @@ -129,7 +132,9 @@ impl NonNull { #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { - &mut *self.as_ptr() + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a mutable reference. + unsafe { &mut *self.as_ptr() } } /// Casts to a pointer of another type. diff --git a/src/libcore/ptr/unique.rs b/src/libcore/ptr/unique.rs index f58d35f06137d..78647eee3389a 100644 --- a/src/libcore/ptr/unique.rs +++ b/src/libcore/ptr/unique.rs @@ -87,7 +87,8 @@ impl Unique { /// `ptr` must be non-null. #[inline] pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { - Unique { pointer: ptr as _, _marker: PhantomData } + // SAFETY: the caller must guarantee that `ptr` is non-null. + unsafe { Unique { pointer: ptr as _, _marker: PhantomData } } } /// Creates a new `Unique` if `ptr` is non-null. @@ -114,7 +115,9 @@ impl Unique { /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. #[inline] pub unsafe fn as_ref(&self) -> &T { - &*self.as_ptr() + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a reference. + unsafe { &*self.as_ptr() } } /// Mutably dereferences the content. @@ -124,7 +127,9 @@ impl Unique { /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. #[inline] pub unsafe fn as_mut(&mut self) -> &mut T { - &mut *self.as_ptr() + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a mutable reference. + unsafe { &mut *self.as_ptr() } } /// Casts to a pointer of another type. diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index ad9c43eccc12e..71d63a7115dbe 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -8,7 +8,6 @@ //! [`std::slice`]: ../../std/slice/index.html #![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] // How this module is organized. // diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index cbbeaa81d4572..0014501d2c4d0 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -7,7 +7,6 @@ //! [`std::str`]: ../../std/str/index.html #![stable(feature = "rust1", since = "1.0.0")] -#![deny(unsafe_op_in_unsafe_fn)] use self::pattern::Pattern; use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 359c39a065f51..fcae6c86774f2 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -115,7 +115,6 @@ #![stable(feature = "rust1", since = "1.0.0")] #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))] #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(unused_imports))] -#![deny(unsafe_op_in_unsafe_fn)] use self::Ordering::*; From 0889d7905050dcf756c38c953889119941a7516b Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 30 Jun 2020 20:19:31 +0200 Subject: [PATCH 66/92] remove duplicate tests --- .../lazy-normalization/issue-71922.rs | 19 ------------------- .../lazy-normalization/issue-71922.stderr | 19 ------------------- 2 files changed, 38 deletions(-) delete mode 100644 src/test/ui/const-generics/lazy-normalization/issue-71922.rs delete mode 100644 src/test/ui/const-generics/lazy-normalization/issue-71922.stderr diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs deleted file mode 100644 index 0d392ddcaedcc..0000000000000 --- a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete -trait Foo {} - -impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} -//~^ ERROR constant expression depends on a generic parameter - -trait FooImpl {} - -impl FooImpl<{ 0u8 == 0u8 }> for [(); 0] {} - -impl FooImpl<{ 0u8 != 0u8 }> for [(); N] {} - -fn foo(_: T) {} - -fn main() { - foo([]); - foo([()]); -} diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr b/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr deleted file mode 100644 index 00917571e716d..0000000000000 --- a/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-71922.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-71922.rs:5:50 - | -LL | impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} - | ^^^^^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - From 3ab7ae39ec77a39df27ac6c3fbde03cd3b763542 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Tue, 19 May 2020 23:26:49 -0400 Subject: [PATCH 67/92] Bring net/parser.rs up to modern up to date with modern rust patterns Made the following changes throughout the IP address parser: - Replaced all uses of `is_some()` / `is_none()` with `?`. - "Upgraded" loops wherever possible; ie, replace `while` with `for`, etc. - Removed all cases of manual index tracking / incrementing. - Renamed several single-character variables with more expressive names. - Replaced several manual control flow segments with equivalent adapters (such as `Option::filter`). - Removed `read_seq_3`; replaced with simple sequences of `?`. - Parser now reslices its state when consuming, rather than carrying a separate state and index variable. - `read_digit` now uses `char::to_digit`. - Removed unnecessary casts back and forth between u8 and u32 - Added comments throughout, especially in the complex IPv6 parsing logic. - Added comprehensive local unit tests for the parser to validate these changes. --- src/libstd/net/parser.rs | 482 +++++++++++++++++++++++---------------- 1 file changed, 289 insertions(+), 193 deletions(-) diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 3f38ee5471081..12d3baf633362 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -10,163 +10,132 @@ use crate::str::FromStr; struct Parser<'a> { // parsing as ASCII, so can use byte array - s: &'a [u8], - pos: usize, + state: &'a [u8], } impl<'a> Parser<'a> { - fn new(s: &'a str) -> Parser<'a> { - Parser { s: s.as_bytes(), pos: 0 } + fn new(input: &'a str) -> Parser<'a> { + Parser { state: input.as_bytes() } } fn is_eof(&self) -> bool { - self.pos == self.s.len() + self.state.is_empty() } - // Commit only if parser returns Some - fn read_atomically(&mut self, cb: F) -> Option + /// Run a parser, and restore the pre-parse state if it fails + fn read_atomically(&mut self, inner: F) -> Option where F: FnOnce(&mut Parser<'_>) -> Option, { - let pos = self.pos; - let r = cb(self); - if r.is_none() { - self.pos = pos; + let state = self.state; + let result = inner(self); + if result.is_none() { + self.state = state; } - r + result } - // Commit only if parser read till EOF - fn read_till_eof(&mut self, cb: F) -> Option + /// Run a parser, but fail if the entire input wasn't consumed. + /// Doesn't run atomically. + fn read_till_eof(&mut self, inner: F) -> Option where F: FnOnce(&mut Parser<'_>) -> Option, { - self.read_atomically(move |p| cb(p).filter(|_| p.is_eof())) + inner(self).filter(|_| self.is_eof()) } - // Apply 3 parsers sequentially - fn read_seq_3(&mut self, pa: PA, pb: PB, pc: PC) -> Option<(A, B, C)> + /// Same as read_till_eof, but returns a Result on failure + fn parse_with(&mut self, inner: F) -> Result where - PA: FnOnce(&mut Parser<'_>) -> Option, - PB: FnOnce(&mut Parser<'_>) -> Option, - PC: FnOnce(&mut Parser<'_>) -> Option, + F: FnOnce(&mut Parser<'_>) -> Option, { - self.read_atomically(move |p| { - let a = pa(p); - let b = if a.is_some() { pb(p) } else { None }; - let c = if b.is_some() { pc(p) } else { None }; - match (a, b, c) { - (Some(a), Some(b), Some(c)) => Some((a, b, c)), - _ => None, - } - }) + self.read_till_eof(inner).ok_or(AddrParseError(())) } - // Read next char + /// Read the next character from the input fn read_char(&mut self) -> Option { - if self.is_eof() { - None - } else { - let r = self.s[self.pos] as char; - self.pos += 1; - Some(r) - } - } - - // Return char and advance iff next char is equal to requested - fn read_given_char(&mut self, c: char) -> Option { - self.read_atomically(|p| match p.read_char() { - Some(next) if next == c => Some(next), - _ => None, + self.state.split_first().map(|(&b, tail)| { + self.state = tail; + b as char }) } - // Read digit - fn read_digit(&mut self, radix: u8) -> Option { - fn parse_digit(c: char, radix: u8) -> Option { - let c = c as u8; - // assuming radix is either 10 or 16 - if c >= b'0' && c <= b'9' { - Some(c - b'0') - } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) { - Some(c - b'a' + 10) - } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) { - Some(c - b'A' + 10) - } else { - None - } - } - - self.read_atomically(|p| p.read_char().and_then(|c| parse_digit(c, radix))) + /// Read the next character from the input if it matches the target + fn read_given_char(&mut self, target: char) -> Option { + self.read_atomically(|p| p.read_char().filter(|&c| c == target)) } - fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { - let mut r = 0; - let mut digit_count = 0; - loop { - match self.read_digit(radix) { - Some(d) => { - r = r * (radix as u32) + (d as u32); - digit_count += 1; - if digit_count > max_digits || r >= upto { - return None; - } - } - None => { - if digit_count == 0 { - return None; - } else { - return Some(r); - } - } - }; - } + /// Helper for reading separators in an indexed loop. Reads the separator + /// character iff index > 0, then runs the parser. When used in a loop, + /// the separator character will only be read on index > 0 (see + /// read_ipv4_addr for an example) + fn read_separator(&mut self, sep: char, index: usize, inner: F) -> Option + where + F: FnOnce(&mut Parser<'_>) -> Option, + { + self.read_atomically(move |p| { + if index > 0 { + let _ = p.read_given_char(sep)?; + } + inner(p) + }) } - // Read number, failing if max_digits of number value exceeded - fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { - self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto)) + // Read a single digit in the given radix. For instance, 0-9 in radix 10; + // 0-9A-F in radix 16. + fn read_digit(&mut self, radix: u32) -> Option { + self.read_atomically(move |p| p.read_char()?.to_digit(radix)) } - fn read_ipv4_addr_impl(&mut self) -> Option { - let mut bs = [0; 4]; - let mut i = 0; - while i < 4 { - if i != 0 && self.read_given_char('.').is_none() { - return None; + // Read a number off the front of the input in the given radix, stopping + // at the first non-digit character or eof. Fails if the number has more + // digits than max_digits, or the value is >= upto, or if there is no number. + fn read_number(&mut self, radix: u32, max_digits: u32, upto: u32) -> Option { + self.read_atomically(move |p| { + let mut result = 0; + let mut digit_count = 0; + + while let Some(digit) = p.read_digit(radix) { + result = (result * radix) + digit; + digit_count += 1; + if digit_count > max_digits || result >= upto { + return None; + } } - bs[i] = self.read_number(10, 3, 0x100).map(|n| n as u8)?; - i += 1; - } - Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3])) + if digit_count == 0 { None } else { Some(result) } + }) } - // Read IPv4 address + /// Read an IPv4 address fn read_ipv4_addr(&mut self) -> Option { - self.read_atomically(|p| p.read_ipv4_addr_impl()) - } + self.read_atomically(|p| { + let mut groups = [0; 4]; - fn read_ipv6_addr_impl(&mut self) -> Option { - fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr { - assert!(head.len() + tail.len() <= 8); - let mut gs = [0; 8]; - gs[..head.len()].copy_from_slice(head); - gs[(8 - tail.len())..8].copy_from_slice(tail); - Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7]) - } + for (i, slot) in groups.iter_mut().enumerate() { + *slot = p.read_separator('.', i, |p| p.read_number(10, 3, 0x100))? as u8; + } + + Some(groups.into()) + }) + } - fn read_groups(p: &mut Parser<'_>, groups: &mut [u16; 8], limit: usize) -> (usize, bool) { - let mut i = 0; - while i < limit { + /// Read an IPV6 Address + fn read_ipv6_addr(&mut self) -> Option { + /// Read a chunk of an ipv6 address into `groups`. Returns the number + /// of groups read, along with a bool indicating if an embedded + /// trailing ipv4 address was read. Specifically, read a series of + /// colon-separated ipv6 groups (0x0000 - 0xFFFF), with an optional + /// trailing embedded ipv4 address. + fn read_groups(p: &mut Parser<'_>, groups: &mut [u16]) -> (usize, bool) { + let limit = groups.len(); + + for (i, slot) in groups.iter_mut().enumerate() { + // Try to read a trailing embedded ipv4 address. There must be + // at least two groups left. if i < limit - 1 { - let ipv4 = p.read_atomically(|p| { - if i == 0 || p.read_given_char(':').is_some() { - p.read_ipv4_addr() - } else { - None - } - }); + let ipv4 = p.read_separator(':', i, |p| p.read_ipv4_addr()); + if let Some(v4_addr) = ipv4 { let octets = v4_addr.octets(); groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16); @@ -175,83 +144,85 @@ impl<'a> Parser<'a> { } } - let group = p.read_atomically(|p| { - if i == 0 || p.read_given_char(':').is_some() { - p.read_number(16, 4, 0x10000).map(|n| n as u16) - } else { - None - } - }); + let group = p.read_separator(':', i, |p| p.read_number(16, 4, 0x10000)); + match group { - Some(g) => groups[i] = g, + Some(g) => *slot = g as u16, None => return (i, false), } - i += 1; } - (i, false) + (groups.len(), false) } - let mut head = [0; 8]; - let (head_size, head_ipv4) = read_groups(self, &mut head, 8); + self.read_atomically(|p| { + // Read the front part of the address; either the whole thing, or up + // to the first :: + let mut head = [0; 8]; + let (head_size, head_ipv4) = read_groups(p, &mut head); - if head_size == 8 { - return Some(Ipv6Addr::new( - head[0], head[1], head[2], head[3], head[4], head[5], head[6], head[7], - )); - } + if head_size == 8 { + return Some(head.into()); + } - // IPv4 part is not allowed before `::` - if head_ipv4 { - return None; - } + // IPv4 part is not allowed before `::` + if head_ipv4 { + return None; + } - // read `::` if previous code parsed less than 8 groups - if self.read_given_char(':').is_none() || self.read_given_char(':').is_none() { - return None; - } + // read `::` if previous code parsed less than 8 groups + // `::` indicates one or more groups of 16 bits of zeros + let _ = p.read_given_char(':')?; + let _ = p.read_given_char(':')?; - let mut tail = [0; 8]; - // `::` indicates one or more groups of 16 bits of zeros - let limit = 8 - (head_size + 1); - let (tail_size, _) = read_groups(self, &mut tail, limit); - Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size])) - } + // Read the back part of the address. The :: must contain at least one + // set of zeroes, so our max length is 7. + let mut tail = [0; 7]; + let limit = 8 - (head_size + 1); + let (tail_size, _) = read_groups(p, &mut tail[..limit]); - fn read_ipv6_addr(&mut self) -> Option { - self.read_atomically(|p| p.read_ipv6_addr_impl()) + // Concat the head and tail of the IP address + head[(8 - tail_size)..8].copy_from_slice(&tail[..tail_size]); + + Some(head.into()) + }) } + /// Read an IP Address, either IPV4 or IPV6. fn read_ip_addr(&mut self) -> Option { - self.read_ipv4_addr().map(IpAddr::V4).or_else(|| self.read_ipv6_addr().map(IpAddr::V6)) + self.read_ipv4_addr().map(IpAddr::V4).or_else(move || self.read_ipv6_addr().map(IpAddr::V6)) } - fn read_socket_addr_v4(&mut self) -> Option { - let ip_addr = |p: &mut Parser<'_>| p.read_ipv4_addr(); - let colon = |p: &mut Parser<'_>| p.read_given_char(':'); - let port = |p: &mut Parser<'_>| p.read_number(10, 5, 0x10000).map(|n| n as u16); + /// Read a : followed by a port in base 10 + fn read_port(&mut self) -> Option { + self.read_atomically(|p| { + let _ = p.read_given_char(':')?; + let port = p.read_number(10, 5, 0x10000)?; + Some(port as u16) + }) + } - self.read_seq_3(ip_addr, colon, port).map(|t| { - let (ip, _, port): (Ipv4Addr, char, u16) = t; - SocketAddrV4::new(ip, port) + /// Read an IPV4 address with a port + fn read_socket_addr_v4(&mut self) -> Option { + self.read_atomically(|p| { + let ip = p.read_ipv4_addr()?; + let port = p.read_port()?; + Some(SocketAddrV4::new(ip, port)) }) } + /// Read an IPV6 address with a port fn read_socket_addr_v6(&mut self) -> Option { - let ip_addr = |p: &mut Parser<'_>| { - let open_br = |p: &mut Parser<'_>| p.read_given_char('['); - let ip_addr = |p: &mut Parser<'_>| p.read_ipv6_addr(); - let clos_br = |p: &mut Parser<'_>| p.read_given_char(']'); - p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1) - }; - let colon = |p: &mut Parser<'_>| p.read_given_char(':'); - let port = |p: &mut Parser<'_>| p.read_number(10, 5, 0x10000).map(|n| n as u16); - - self.read_seq_3(ip_addr, colon, port).map(|t| { - let (ip, _, port): (Ipv6Addr, char, u16) = t; - SocketAddrV6::new(ip, port, 0, 0) + self.read_atomically(|p| { + let _ = p.read_given_char('[')?; + let ip = p.read_ipv6_addr()?; + let _ = p.read_given_char(']')?; + + let port = p.read_port()?; + Some(SocketAddrV6::new(ip, port, 0, 0)) }) } + /// Read an IP address with a port fn read_socket_addr(&mut self) -> Option { self.read_socket_addr_v4() .map(SocketAddr::V4) @@ -263,10 +234,7 @@ impl<'a> Parser<'a> { impl FromStr for IpAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } + Parser::new(s).parse_with(|p| p.read_ip_addr()) } } @@ -274,10 +242,7 @@ impl FromStr for IpAddr { impl FromStr for Ipv4Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } + Parser::new(s).parse_with(|p| p.read_ipv4_addr()) } } @@ -285,10 +250,7 @@ impl FromStr for Ipv4Addr { impl FromStr for Ipv6Addr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } + Parser::new(s).parse_with(|p| p.read_ipv6_addr()) } } @@ -296,10 +258,7 @@ impl FromStr for Ipv6Addr { impl FromStr for SocketAddrV4 { type Err = AddrParseError; fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } + Parser::new(s).parse_with(|p| p.read_socket_addr_v4()) } } @@ -307,10 +266,7 @@ impl FromStr for SocketAddrV4 { impl FromStr for SocketAddrV6 { type Err = AddrParseError; fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } + Parser::new(s).parse_with(|p| p.read_socket_addr_v6()) } } @@ -318,10 +274,7 @@ impl FromStr for SocketAddrV6 { impl FromStr for SocketAddr { type Err = AddrParseError; fn from_str(s: &str) -> Result { - match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) { - Some(s) => Ok(s), - None => Err(AddrParseError(())), - } + Parser::new(s).parse_with(|p| p.read_socket_addr()) } } @@ -376,3 +329,146 @@ impl Error for AddrParseError { "invalid IP address syntax" } } + +#[cfg(test)] +mod tests { + // FIXME: These tests are all excellent candidates for AFL fuzz testing + use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; + use crate::str::FromStr; + + const PORT: u16 = 8080; + + const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1); + const IPV4_STR: &str = "192.168.0.1"; + const IPV4_STR_PORT: &str = "192.168.0.1:8080"; + + const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1); + const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; + const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; + const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; + const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; + + #[test] + fn parse_ipv4() { + let result: Ipv4Addr = IPV4_STR.parse().unwrap(); + assert_eq!(result, IPV4); + + assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err()); + } + + #[test] + fn parse_ipv6() { + let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap(); + assert_eq!(result, IPV6); + + let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap(); + assert_eq!(result, IPV6); + + let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap(); + assert_eq!(result, IPV6); + + assert!(Ipv6Addr::from_str(IPV4_STR).is_err()); + assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err()); + assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err()); + } + + #[test] + fn parse_ip() { + let result: IpAddr = IPV4_STR.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV4)); + + let result: IpAddr = IPV6_STR_FULL.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + let result: IpAddr = IPV6_STR_V4.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + assert!(IpAddr::from_str(IPV4_STR_PORT).is_err()); + assert!(IpAddr::from_str(IPV6_STR_PORT).is_err()); + } + + #[test] + fn parse_socket_v4() { + let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddrV4::new(IPV4, PORT)); + + assert!(SocketAddrV4::from_str(IPV4_STR).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err()); + } + + #[test] + fn parse_socket_v6() { + let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0)); + + assert!(SocketAddrV6::from_str(IPV4_STR).is_err()); + assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err()); + } + + #[test] + fn parse_socket() { + let result: SocketAddr = IPV4_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddr::from((IPV4, PORT))); + + let result: SocketAddr = IPV6_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddr::from((IPV6, PORT))); + + assert!(SocketAddr::from_str(IPV4_STR).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_V4).is_err()); + } + + #[test] + fn ipv6_corner_cases() { + let result: Ipv6Addr = "1::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "1:1::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "::1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + + let result: Ipv6Addr = "::1:1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1)); + + let result: Ipv6Addr = "::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "::192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1)); + + let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1)); + + let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1)); + } + + // Things that might not seem like failures but are + #[test] + fn ipv6_corner_failures() { + // No IP address before the :: + assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err()); + + // :: must have at least 1 set of zeroes + assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err()); + + // Need brackets for a port + assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err()); + } +} From 6a7a6528f69ddb32574e486471c400fee6de8fd7 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Tue, 30 Jun 2020 20:14:54 +0200 Subject: [PATCH 68/92] Bless failing tests --- src/test/ui/consts/miri_unleashed/drop.stderr | 4 +- src/test/ui/consts/offset_from_ub.stderr | 60 ++++---- src/test/ui/consts/offset_ub.stderr | 132 +++++++++--------- ...-38591-non-regular-dropck-recursion.stderr | 8 +- 4 files changed, 105 insertions(+), 99 deletions(-) diff --git a/src/test/ui/consts/miri_unleashed/drop.stderr b/src/test/ui/consts/miri_unleashed/drop.stderr index 34ab5155e22d0..1fa3992cc5afd 100644 --- a/src/test/ui/consts/miri_unleashed/drop.stderr +++ b/src/test/ui/consts/miri_unleashed/drop.stderr @@ -4,7 +4,9 @@ error[E0080]: could not evaluate static initializer LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { LL | | // Code here does not matter - this is replaced by the LL | | // real drop glue by the compiler. -LL | | drop_in_place(to_drop) +LL | | +LL | | // SAFETY: see comment above +LL | | unsafe { drop_in_place(to_drop) } LL | | } | | ^ | | | diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index cde2fe3262692..aa65f4de3e17e 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -1,12 +1,12 @@ error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::ptr_offset_from(self, origin) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | ptr_offset_from cannot compute offset of pointers into different allocations. - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `DIFFERENT_ALLOC` at $DIR/offset_from_ub.rs:17:27 +LL | unsafe { intrinsics::ptr_offset_from(self, origin) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | ptr_offset_from cannot compute offset of pointers into different allocations. + | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `DIFFERENT_ALLOC` at $DIR/offset_from_ub.rs:17:27 | ::: $DIR/offset_from_ub.rs:11:1 | @@ -24,12 +24,12 @@ LL | | }; error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::ptr_offset_from(self, origin) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `NOT_PTR` at $DIR/offset_from_ub.rs:23:14 +LL | unsafe { intrinsics::ptr_offset_from(self, origin) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn bytes into a pointer + | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `NOT_PTR` at $DIR/offset_from_ub.rs:23:14 | ::: $DIR/offset_from_ub.rs:21:1 | @@ -42,12 +42,12 @@ LL | | }; error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::ptr_offset_from(self, origin) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | exact_div: 1_isize cannot be divided by 2_isize without remainder - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:31:14 +LL | unsafe { intrinsics::ptr_offset_from(self, origin) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | exact_div: 1_isize cannot be divided by 2_isize without remainder + | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:31:14 | ::: $DIR/offset_from_ub.rs:26:1 | @@ -63,12 +63,12 @@ LL | | }; error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::ptr_offset_from(self, origin) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | inbounds test failed: 0x0 is not a valid pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:37:14 +LL | unsafe { intrinsics::ptr_offset_from(self, origin) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: 0x0 is not a valid pointer + | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:37:14 | ::: $DIR/offset_from_ub.rs:34:1 | @@ -82,12 +82,12 @@ LL | | }; error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::ptr_offset_from(self, origin) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `DIFFERENT_INT` at $DIR/offset_from_ub.rs:44:14 +LL | unsafe { intrinsics::ptr_offset_from(self, origin) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn bytes into a pointer + | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `DIFFERENT_INT` at $DIR/offset_from_ub.rs:44:14 | ::: $DIR/offset_from_ub.rs:40:1 | diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index 0ab81cc0c5b31..0a144a6bac2f1 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -1,12 +1,12 @@ error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `BEFORE_START` at $DIR/offset_ub.rs:7:46 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `BEFORE_START` at $DIR/offset_ub.rs:7:46 | ::: $DIR/offset_ub.rs:7:1 | @@ -18,12 +18,12 @@ LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `AFTER_END` at $DIR/offset_ub.rs:8:43 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `AFTER_END` at $DIR/offset_ub.rs:8:43 | ::: $DIR/offset_ub.rs:8:1 | @@ -33,12 +33,12 @@ LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45 | ::: $DIR/offset_ub.rs:9:1 | @@ -48,12 +48,12 @@ LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `OVERFLOW` at $DIR/offset_ub.rs:11:43 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `OVERFLOW` at $DIR/offset_ub.rs:11:43 | ::: $DIR/offset_ub.rs:11:1 | @@ -63,12 +63,12 @@ LL | pub const OVERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize:: error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44 | ::: $DIR/offset_ub.rs:12:1 | @@ -78,12 +78,12 @@ LL | pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize: error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56 | ::: $DIR/offset_ub.rs:13:1 | @@ -93,12 +93,12 @@ LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *cons error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | overflowing in-bounds pointer arithmetic + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57 | ::: $DIR/offset_ub.rs:14:1 | @@ -108,12 +108,12 @@ LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).of error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0 + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50 | ::: $DIR/offset_ub.rs:16:1 | @@ -123,12 +123,12 @@ LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1 error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) as *mut T - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unable to turn bytes into a pointer - | inside `std::ptr::mut_ptr::::offset` at $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL - | inside `DANGLING` at $DIR/offset_ub.rs:17:42 +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn bytes into a pointer + | inside `std::ptr::mut_ptr::::offset` at $SRC_DIR/libcore/ptr/mut_ptr.rs:LL:COL + | inside `DANGLING` at $DIR/offset_ub.rs:17:42 | ::: $DIR/offset_ub.rs:17:1 | @@ -138,12 +138,12 @@ LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | inbounds test failed: 0x0 is not a valid pointer - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | inbounds test failed: 0x0 is not a valid pointer + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50 | ::: $DIR/offset_ub.rs:20:1 | @@ -153,12 +153,12 @@ LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::().offset(0 error: any use of this value will cause an error --> $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL | -LL | intrinsics::offset(self, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL - | inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:23:47 +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn bytes into a pointer + | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/libcore/ptr/const_ptr.rs:LL:COL + | inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:23:47 | ::: $DIR/offset_ub.rs:23:1 | diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index 0552847c48ca9..3296a2cb094a1 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -4,7 +4,9 @@ error: reached the recursion limit while instantiating `std::intrinsics::drop_in LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { LL | | // Code here does not matter - this is replaced by the LL | | // real drop glue by the compiler. -LL | | drop_in_place(to_drop) +LL | | +LL | | // SAFETY: see comment above +LL | | unsafe { drop_in_place(to_drop) } LL | | } | |_^ | @@ -14,7 +16,9 @@ note: `std::intrinsics::drop_in_place` defined here LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { LL | | // Code here does not matter - this is replaced by the LL | | // real drop glue by the compiler. -LL | | drop_in_place(to_drop) +LL | | +LL | | // SAFETY: see comment above +LL | | unsafe { drop_in_place(to_drop) } LL | | } | |_^ From 37a48fa838e73f2c008bbbbd0db555f4852be354 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 30 Jun 2020 14:41:37 -0400 Subject: [PATCH 69/92] Add force-host to test aux file used by proc-macro --- src/test/ui/proc-macro/auxiliary/make-macro.rs | 2 ++ src/test/ui/proc-macro/meta-macro-hygiene.stdout | 2 +- src/test/ui/proc-macro/meta-macro.stdout | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/ui/proc-macro/auxiliary/make-macro.rs b/src/test/ui/proc-macro/auxiliary/make-macro.rs index 155d54ea0bfb0..2c21221fbb0f5 100644 --- a/src/test/ui/proc-macro/auxiliary/make-macro.rs +++ b/src/test/ui/proc-macro/auxiliary/make-macro.rs @@ -1,3 +1,5 @@ +// force-host + #[macro_export] macro_rules! make_it { ($name:ident) => { diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index acff85bd6b233..daca40eda9006 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,4 +1,4 @@ -Def site: $DIR/auxiliary/make-macro.rs:5:9: 8:10 (#3) +Def site: $DIR/auxiliary/make-macro.rs:7:9: 10:10 (#3) #![feature /* 0#0 */(prelude_import)] #[prelude_import /* 0#1 */] use std /* 0#1 */::prelude /* 0#1 */::v1 /* 0#1 */::*; diff --git a/src/test/ui/proc-macro/meta-macro.stdout b/src/test/ui/proc-macro/meta-macro.stdout index 00439bc292081..fa79f72137f64 100644 --- a/src/test/ui/proc-macro/meta-macro.stdout +++ b/src/test/ui/proc-macro/meta-macro.stdout @@ -1 +1 @@ -Def site: $DIR/auxiliary/make-macro.rs:5:9: 8:10 (#3) +Def site: $DIR/auxiliary/make-macro.rs:7:9: 10:10 (#3) From e1913587889b0b1147531c370d9c810b46b5971e Mon Sep 17 00:00:00 2001 From: aspen Date: Tue, 30 Jun 2020 17:21:49 -0400 Subject: [PATCH 70/92] Changes required for rustc/cargo to build for iOS targets --- src/bootstrap/lib.rs | 5 +++++ src/bootstrap/native.rs | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b611af54565ac..b11a7fc6255f3 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -811,6 +811,11 @@ impl Build { if target.contains("apple-darwin") { base.push("-stdlib=libc++".into()); } + + // Required for LLVM to properly compile. + if target.contains("apple-ios") { + base.push("-miphoneos-version-min=10.0".into()); + } // Work around an apparently bad MinGW / GCC optimization, // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 106db90b2d0f0..e35ffb304bcfa 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -175,6 +175,14 @@ impl Step for Llvm { cfg.define("LLVM_ENABLE_ZLIB", "OFF"); } + // Are we compiling for iOS/tvOS? + if target.contains("apple") && !target.contains("darwin") { + cfg.define("CMAKE_OSX_SYSROOT", "/"); + cfg.define("CMAKE_OSX_DEPLOYMENT_TARGET", ""); + cfg.define("LLVM_ENABLE_PLUGINS", "OFF"); // Prevent cmake from adding -bundle to CFLAGS automatically. + cfg.define("LLVM_ENABLE_ZLIB", "OFF"); + } + if builder.config.llvm_thin_lto { cfg.define("LLVM_ENABLE_LTO", "Thin"); if !target.contains("apple") { From c22bcb03814a1600d17097123813495ea0a40796 Mon Sep 17 00:00:00 2001 From: aspen Date: Tue, 30 Jun 2020 17:56:31 -0400 Subject: [PATCH 71/92] Only set the flag in LLVM builds. --- src/bootstrap/lib.rs | 5 ----- src/bootstrap/native.rs | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b11a7fc6255f3..b611af54565ac 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -811,11 +811,6 @@ impl Build { if target.contains("apple-darwin") { base.push("-stdlib=libc++".into()); } - - // Required for LLVM to properly compile. - if target.contains("apple-ios") { - base.push("-miphoneos-version-min=10.0".into()); - } // Work around an apparently bad MinGW / GCC optimization, // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index e35ffb304bcfa..c10e8723422a9 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -420,6 +420,9 @@ fn configure_cmake( if let Some(ref s) = builder.config.llvm_cflags { cflags.push_str(&format!(" {}", s)); } + if target.contains("apple-ios") { + cflags.push_str(" -miphoneos-version-min=10.0"); + } cfg.define("CMAKE_C_FLAGS", cflags); let mut cxxflags = builder.cflags(target, GitRepo::Llvm).join(" "); if builder.config.llvm_static_stdcpp && !target.contains("msvc") && !target.contains("netbsd") { From 5f3dbd83af1a2872ec2514ea1a18116b800e4aeb Mon Sep 17 00:00:00 2001 From: aspen Date: Tue, 30 Jun 2020 18:18:19 -0400 Subject: [PATCH 72/92] Don't break on iOS Simulator builds. --- src/bootstrap/native.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index c10e8723422a9..8d50dd0a9043b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -421,7 +421,11 @@ fn configure_cmake( cflags.push_str(&format!(" {}", s)); } if target.contains("apple-ios") { - cflags.push_str(" -miphoneos-version-min=10.0"); + if target.contains("86-") { + cflags.push_str(" -miphonesimulator-version-min=10.0"); + } else { + cflags.push_str(" -miphoneos-version-min=10.0"); + } } cfg.define("CMAKE_C_FLAGS", cflags); let mut cxxflags = builder.cflags(target, GitRepo::Llvm).join(" "); From 51858dae1e0008f0cef35b5ba73ff115ed8f3c1e Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Tue, 30 Jun 2020 18:42:55 -0400 Subject: [PATCH 73/92] Make #[target_feature] Fn trait error message less confusing --- .../traits/error_reporting/mod.rs | 31 +++++++++---------- .../fn-traits.stderr | 12 +++---- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 76e01a40a2362..ade3dee0b1286 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -286,18 +286,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .starts_with("std::convert::From<"); let is_unsize = { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() }; - let is_fn_trait = [ - self.tcx.lang_items().fn_trait(), - self.tcx.lang_items().fn_mut_trait(), - self.tcx.lang_items().fn_once_trait(), - ] - .contains(&Some(trait_ref.def_id())); - let is_target_feature_fn = - if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind { - !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() - } else { - false - }; let (message, note) = if is_try && is_from { ( Some(format!( @@ -439,11 +427,22 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); } + let is_fn_trait = [ + self.tcx.lang_items().fn_trait(), + self.tcx.lang_items().fn_mut_trait(), + self.tcx.lang_items().fn_once_trait(), + ] + .contains(&Some(trait_ref.def_id())); + let is_target_feature_fn = + if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind { + !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() + } else { + false + }; if is_fn_trait && is_target_feature_fn { - err.note(&format!( - "`{}` has `#[target_feature]` and is unsafe to call", - trait_ref.skip_binder().self_ty(), - )); + err.note( + "`#[target_feature]` functions do not implement the `Fn` traits", + ); } // Try to report a help message diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index ba3d2eac1a6b0..448077b439e80 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -9,7 +9,7 @@ LL | call(foo); | = help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } - = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call + = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:25:14 @@ -22,7 +22,7 @@ LL | call_mut(foo); | = help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } - = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call + = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:26:15 @@ -35,7 +35,7 @@ LL | call_once(foo); | = help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ } - = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call + = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:28:10 @@ -48,7 +48,7 @@ LL | call(foo_unsafe); | = help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } - = note: `unsafe fn() {foo_unsafe}` has `#[target_feature]` and is unsafe to call + = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:30:14 @@ -61,7 +61,7 @@ LL | call_mut(foo_unsafe); | = help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } - = note: `unsafe fn() {foo_unsafe}` has `#[target_feature]` and is unsafe to call + = note: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:32:15 @@ -74,7 +74,7 @@ LL | call_once(foo_unsafe); | = help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ } - = note: `unsafe fn() {foo_unsafe}` has `#[target_feature]` and is unsafe to call + = note: `#[target_feature]` functions do not implement the `Fn` traits error: aborting due to 6 previous errors From 0d265129645f863202aedcba27f5bc6edbe29d11 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 1 Jul 2020 09:33:21 +0900 Subject: [PATCH 74/92] Add missing backtick in `ty_error_with_message` --- src/librustc_middle/ty/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index e2f601371b1ee..c6f1bfd7fff54 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1169,7 +1169,7 @@ impl<'tcx> TyCtxt<'tcx> { self.ty_error_with_message(DUMMY_SP, "TyKind::Error constructed but no error reported") } - /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg to + /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to /// ensure it gets used. #[track_caller] pub fn ty_error_with_message>(self, span: S, msg: &str) -> Ty<'tcx> { From 47425e476b8fd087799d1229a23f7aa81c1835bf Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 30 Jun 2020 17:53:45 -0700 Subject: [PATCH 75/92] Rewrite a few manual index loops with while-let There were a few instances of this pattern: ```rust while index < vec.len() { let item = &vec[index]; // ... } ``` These can be indexed at once: ```rust while let Some(item) = vec.get(index) { // ... } ``` Particularly in `ObligationForest::process_obligations`, this mitigates a codegen regression found with LLVM 11 (#73526). --- src/librustc_data_structures/obligation_forest/mod.rs | 10 ++++------ src/librustc_data_structures/transitive_relation.rs | 6 ++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 197169b7036e0..7cf5202d919f8 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -412,9 +412,7 @@ impl ObligationForest { // be computed with the initial length, and we would miss the appended // nodes. Therefore we use a `while` loop. let mut index = 0; - while index < self.nodes.len() { - let node = &mut self.nodes[index]; - + while let Some(node) = self.nodes.get_mut(index) { // `processor.process_obligation` can modify the predicate within // `node.obligation`, and that predicate is the key used for // `self.active_cache`. This means that `self.active_cache` can get @@ -666,8 +664,8 @@ impl ObligationForest { for node in &mut self.nodes { let mut i = 0; - while i < node.dependents.len() { - let new_index = node_rewrites[node.dependents[i]]; + while let Some(dependent) = node.dependents.get_mut(i) { + let new_index = node_rewrites[*dependent]; if new_index >= orig_nodes_len { node.dependents.swap_remove(i); if i == 0 && node.has_parent { @@ -675,7 +673,7 @@ impl ObligationForest { node.has_parent = false; } } else { - node.dependents[i] = new_index; + *dependent = new_index; i += 1; } } diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index de503fe8228aa..189da3395ad1b 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -391,14 +391,12 @@ impl TransitiveRelation { /// - Input: `[a, x, b, y]`. Output: `[a, x]`. fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { let mut i = 0; - while i < candidates.len() { - let candidate_i = candidates[i]; + while let Some(&candidate_i) = candidates.get(i) { i += 1; let mut j = i; let mut dead = 0; - while j < candidates.len() { - let candidate_j = candidates[j]; + while let Some(&candidate_j) = candidates.get(j) { if closure.contains(candidate_i, candidate_j) { // If `i` can reach `j`, then we can remove `j`. So just // mark it as dead and move on; subsequent indices will be From 7616cd9ee9c2eb0cec7b76d608af7c8fad7704d4 Mon Sep 17 00:00:00 2001 From: Elton Law Date: Tue, 30 Jun 2020 22:51:28 -0400 Subject: [PATCH 76/92] `#[deny(unsafe_op_in_unsafe_fn)]` in libstd/fs.rs --- src/libstd/fs.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 17f890375f843..bdcbd46c0d813 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -666,7 +666,8 @@ impl Read for File { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } #[stable(feature = "rust1", since = "1.0.0")] @@ -711,7 +712,8 @@ impl Read for &File { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } #[stable(feature = "rust1", since = "1.0.0")] From b438811029edfb3f39451c91d7e107e0338cf043 Mon Sep 17 00:00:00 2001 From: Elton Law Date: Tue, 30 Jun 2020 23:09:06 -0400 Subject: [PATCH 77/92] enable unsafe_op_in_unsafe_fn lint --- src/libstd/fs.rs | 1 + src/libstd/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index bdcbd46c0d813..4d031cb7a52e4 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -8,6 +8,7 @@ //! extension traits of `std::os::$platform`. #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] use crate::ffi::OsString; use crate::fmt; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ef699ede2a140..1833d35bdde31 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -319,6 +319,7 @@ #![feature(track_caller)] #![feature(try_reserve)] #![feature(unboxed_closures)] +#![feature(unsafe_block_in_unsafe_fn)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] From f07d10db7cf9a985c5fcb4187825642207134970 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Thu, 21 May 2020 16:43:39 -0700 Subject: [PATCH 78/92] Stabilize `#[track_caller]`. Does not yet make its constness stable, though. Use of `Location::caller` in const contexts is still gated by `#![feature(const_caller_location)]`. --- .../src/language-features/track-caller.md | 5 ----- src/libcore/lib.rs | 2 +- src/libcore/macros/mod.rs | 2 +- src/libcore/panic.rs | 14 ++++---------- src/librustc_error_codes/error_codes/E0736.md | 2 -- src/librustc_error_codes/error_codes/E0737.md | 2 -- src/librustc_error_codes/error_codes/E0739.md | 1 - src/librustc_errors/lib.rs | 2 +- src/librustc_feature/accepted.rs | 3 +++ src/librustc_feature/active.rs | 4 ---- src/librustc_feature/builtin_attrs.rs | 2 +- src/librustc_middle/lib.rs | 2 +- src/libstd/lib.rs | 2 +- src/test/ui/asm/sym.rs | 2 +- .../ui/feature-gates/feature-gate-track_caller.rs | 5 ----- .../feature-gates/feature-gate-track_caller.stderr | 12 ------------ src/test/ui/macros/issue-68060.rs | 2 -- src/test/ui/macros/issue-68060.stderr | 6 +++--- .../numbers-arithmetic/saturating-float-casts.rs | 1 - src/test/ui/rfc-2091-track-caller/call-chain.rs | 2 -- .../caller-location-fnptr-rt-ctfe-equiv.rs | 2 +- .../caller-location-intrinsic.rs | 6 ++---- .../rfc-2091-track-caller/const-caller-location.rs | 2 +- .../diverging-caller-location.rs | 2 -- .../ui/rfc-2091-track-caller/error-odd-syntax.rs | 2 -- .../rfc-2091-track-caller/error-odd-syntax.stderr | 2 +- .../error-with-invalid-abi.rs | 2 -- .../error-with-invalid-abi.stderr | 4 ++-- .../ui/rfc-2091-track-caller/error-with-naked.rs | 2 +- .../ui/rfc-2091-track-caller/intrinsic-wrapper.rs | 6 ++---- src/test/ui/rfc-2091-track-caller/only-for-fns.rs | 2 -- .../ui/rfc-2091-track-caller/only-for-fns.stderr | 2 +- src/test/ui/rfc-2091-track-caller/pass.rs | 2 -- .../track-caller-attribute.rs | 10 ++++------ .../ui/rfc-2091-track-caller/track-caller-ffi.rs | 10 ++++------ .../tracked-fn-ptr-with-arg.rs | 2 -- .../ui/rfc-2091-track-caller/tracked-fn-ptr.rs | 2 -- .../rfc-2091-track-caller/tracked-trait-impls.rs | 2 -- 38 files changed, 36 insertions(+), 99 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/track-caller.md delete mode 100644 src/test/ui/feature-gates/feature-gate-track_caller.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-track_caller.stderr diff --git a/src/doc/unstable-book/src/language-features/track-caller.md b/src/doc/unstable-book/src/language-features/track-caller.md deleted file mode 100644 index afc11a2b9492c..0000000000000 --- a/src/doc/unstable-book/src/language-features/track-caller.md +++ /dev/null @@ -1,5 +0,0 @@ -# `track_caller` - -The tracking issue for this feature is: [#47809](https://github.com/rust-lang/rust/issues/47809). - ------------------------- diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index aeb52bffbf24c..b732dacae1c5b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -118,7 +118,7 @@ #![feature(staged_api)] #![feature(std_internals)] #![feature(stmt_expr_attributes)] -#![feature(track_caller)] +#![cfg_attr(bootstrap, feature(track_caller))] #![feature(transparent_unions)] #![feature(unboxed_closures)] #![feature(unsized_locals)] diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index 3cfdde60135b7..13c0e8daf740f 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -1,6 +1,6 @@ #[doc(include = "panic.md")] #[macro_export] -#[allow_internal_unstable(core_panic, track_caller)] +#[allow_internal_unstable(core_panic, const_caller_location)] #[stable(feature = "core", since = "1.6.0")] macro_rules! panic { () => ( diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index c7009b76e8148..543aa969330ae 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -190,7 +190,6 @@ impl<'a> Location<'a> { /// # Examples /// /// ``` - /// #![feature(track_caller)] /// use core::panic::Location; /// /// /// Returns the [`Location`] at which it is called. @@ -206,7 +205,7 @@ impl<'a> Location<'a> { /// /// let fixed_location = get_just_one_location(); /// assert_eq!(fixed_location.file(), file!()); - /// assert_eq!(fixed_location.line(), 15); + /// assert_eq!(fixed_location.line(), 14); /// assert_eq!(fixed_location.column(), 5); /// /// // running the same untracked function in a different location gives us the same result @@ -217,7 +216,7 @@ impl<'a> Location<'a> { /// /// let this_location = get_caller_location(); /// assert_eq!(this_location.file(), file!()); - /// assert_eq!(this_location.line(), 29); + /// assert_eq!(this_location.line(), 28); /// assert_eq!(this_location.column(), 21); /// /// // running the tracked function in a different location produces a different value @@ -226,13 +225,8 @@ impl<'a> Location<'a> { /// assert_ne!(this_location.line(), another_location.line()); /// assert_ne!(this_location.column(), another_location.column()); /// ``` - // FIXME: When stabilizing this method, please also update the documentation - // of `intrinsics::caller_location`. - #[unstable( - feature = "track_caller", - reason = "uses #[track_caller] which is not yet stable", - issue = "47809" - )] + #[stable(feature = "track_caller", since = "1.46.0")] + #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] #[track_caller] pub const fn caller() -> &'static Location<'static> { crate::intrinsics::caller_location() diff --git a/src/librustc_error_codes/error_codes/E0736.md b/src/librustc_error_codes/error_codes/E0736.md index 8a60dc320599b..0f3d41ba66dc4 100644 --- a/src/librustc_error_codes/error_codes/E0736.md +++ b/src/librustc_error_codes/error_codes/E0736.md @@ -3,8 +3,6 @@ Erroneous code example: ```compile_fail,E0736 -#![feature(track_caller)] - #[naked] #[track_caller] fn foo() {} diff --git a/src/librustc_error_codes/error_codes/E0737.md b/src/librustc_error_codes/error_codes/E0737.md index c6553e97b7e91..ab5e60692b4da 100644 --- a/src/librustc_error_codes/error_codes/E0737.md +++ b/src/librustc_error_codes/error_codes/E0737.md @@ -5,8 +5,6 @@ restrictions. Erroneous code example: ```compile_fail,E0737 -#![feature(track_caller)] - #[track_caller] extern "C" fn foo() {} ``` diff --git a/src/librustc_error_codes/error_codes/E0739.md b/src/librustc_error_codes/error_codes/E0739.md index 707751066edbc..8d9039bef93f6 100644 --- a/src/librustc_error_codes/error_codes/E0739.md +++ b/src/librustc_error_codes/error_codes/E0739.md @@ -3,7 +3,6 @@ Erroneous code example: ```compile_fail,E0739 -#![feature(track_caller)] #[track_caller] struct Bar { a: u8, diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 0c1418d3cad27..362913ceadf18 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -5,7 +5,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(crate_visibility_modifier)] #![feature(nll)] -#![feature(track_caller)] +#![cfg_attr(bootstrap, feature(track_caller))] pub use emitter::ColorConfig; diff --git a/src/librustc_feature/accepted.rs b/src/librustc_feature/accepted.rs index b164b21913d6e..d93c17b05b498 100644 --- a/src/librustc_feature/accepted.rs +++ b/src/librustc_feature/accepted.rs @@ -265,6 +265,9 @@ declare_features! ( (accepted, const_if_match, "1.45.0", Some(49146), None), /// Allows the use of `loop` and `while` in constants. (accepted, const_loop, "1.45.0", Some(52000), None), + /// Allows `#[track_caller]` to be used which provides + /// accurate caller location reporting during panic (RFC 2091). + (accepted, track_caller, "1.46.0", Some(47809), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 8660d6a8d6410..b9a55377949f2 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -494,10 +494,6 @@ declare_features! ( /// Allows the use of raw-dylibs (RFC 2627). (active, raw_dylib, "1.40.0", Some(58713), None), - /// Allows `#[track_caller]` to be used which provides - /// accurate caller location reporting during panic (RFC 2091). - (active, track_caller, "1.40.0", Some(47809), None), - /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs index 524a357971029..c9a34f033758b 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/src/librustc_feature/builtin_attrs.rs @@ -260,6 +260,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ungated!(cold, Whitelisted, template!(Word)), ungated!(no_builtins, Whitelisted, template!(Word)), ungated!(target_feature, Whitelisted, template!(List: r#"enable = "name""#)), + ungated!(track_caller, Whitelisted, template!(Word)), gated!( no_sanitize, Whitelisted, template!(List: "address, memory, thread"), @@ -333,7 +334,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ gated!(ffi_returns_twice, Whitelisted, template!(Word), experimental!(ffi_returns_twice)), gated!(ffi_pure, Whitelisted, template!(Word), experimental!(ffi_pure)), gated!(ffi_const, Whitelisted, template!(Word), experimental!(ffi_const)), - gated!(track_caller, Whitelisted, template!(Word), experimental!(track_caller)), gated!( register_attr, CrateLevel, template!(List: "attr1, attr2, ..."), experimental!(register_attr), diff --git a/src/librustc_middle/lib.rs b/src/librustc_middle/lib.rs index 676346fbebdd1..96b8ca27183ed 100644 --- a/src/librustc_middle/lib.rs +++ b/src/librustc_middle/lib.rs @@ -42,7 +42,7 @@ #![feature(or_patterns)] #![feature(range_is_empty)] #![feature(min_specialization)] -#![feature(track_caller)] +#![cfg_attr(bootstrap, feature(track_caller))] #![feature(trusted_len)] #![feature(stmt_expr_attributes)] #![feature(test)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index ef699ede2a140..372038df54f2e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -316,7 +316,7 @@ #![feature(toowned_clone_into)] #![feature(total_cmp)] #![feature(trace_macros)] -#![feature(track_caller)] +#![cfg_attr(bootstrap, feature(track_caller))] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(untagged_unions)] diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs index 8cff16aa75f69..9931697e4129c 100644 --- a/src/test/ui/asm/sym.rs +++ b/src/test/ui/asm/sym.rs @@ -3,7 +3,7 @@ // only-linux // run-pass -#![feature(asm, track_caller, thread_local)] +#![feature(asm, thread_local)] extern "C" fn f1() -> i32 { 111 diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.rs b/src/test/ui/feature-gates/feature-gate-track_caller.rs deleted file mode 100644 index 5865cf0a4f754..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-track_caller.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[track_caller] -fn f() {} -//~^^ ERROR the `#[track_caller]` attribute is an experimental feature - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-track_caller.stderr b/src/test/ui/feature-gates/feature-gate-track_caller.stderr deleted file mode 100644 index 8ceab501617ee..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-track_caller.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: the `#[track_caller]` attribute is an experimental feature - --> $DIR/feature-gate-track_caller.rs:1:1 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ - | - = note: see issue #47809 for more information - = help: add `#![feature(track_caller)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs index bc70f8ffec2b2..8772e98b6e9bb 100644 --- a/src/test/ui/macros/issue-68060.rs +++ b/src/test/ui/macros/issue-68060.rs @@ -1,5 +1,3 @@ -#![feature(track_caller)] - fn main() { (0..) .map( diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index 22187c4a4098a..b9b2f946c5967 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -1,5 +1,5 @@ error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/issue-68060.rs:6:13 + --> $DIR/issue-68060.rs:4:13 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,13 +11,13 @@ LL | |_| (), = help: add `#![feature(target_feature_11)]` to the crate attributes to enable error: the feature named `` is not valid for this target - --> $DIR/issue-68060.rs:6:30 + --> $DIR/issue-68060.rs:4:30 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^ `` is not valid for this target error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/issue-68060.rs:9:13 + --> $DIR/issue-68060.rs:7:13 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numbers-arithmetic/saturating-float-casts.rs b/src/test/ui/numbers-arithmetic/saturating-float-casts.rs index e6d0c94a02fac..825a11972aeeb 100644 --- a/src/test/ui/numbers-arithmetic/saturating-float-casts.rs +++ b/src/test/ui/numbers-arithmetic/saturating-float-casts.rs @@ -9,7 +9,6 @@ // merged. #![feature(test, stmt_expr_attributes)] -#![feature(track_caller)] #![deny(overflowing_literals)] extern crate test; diff --git a/src/test/ui/rfc-2091-track-caller/call-chain.rs b/src/test/ui/rfc-2091-track-caller/call-chain.rs index 3f1c8f7abe8b8..fefb84de729fe 100644 --- a/src/test/ui/rfc-2091-track-caller/call-chain.rs +++ b/src/test/ui/rfc-2091-track-caller/call-chain.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(track_caller)] - use std::panic::Location; struct Foo; diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs index edf9ba2c41a15..05240908917bc 100644 --- a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs +++ b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs @@ -6,7 +6,7 @@ // run-pass // compile-flags: -Z unleash-the-miri-inside-of-you -#![feature(core_intrinsics, const_caller_location, track_caller, const_fn)] +#![feature(core_intrinsics, const_caller_location, const_fn)] type L = &'static std::panic::Location<'static>; diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs index 090e912c1d0ba..f244b74e391ff 100644 --- a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs +++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(track_caller)] - #[inline(never)] #[track_caller] fn codegen_caller_loc() -> &'static core::panic::Location<'static> { @@ -15,13 +13,13 @@ macro_rules! caller_location_from_macro { fn main() { let loc = codegen_caller_loc(); assert_eq!(loc.file(), file!()); - assert_eq!(loc.line(), 16); + assert_eq!(loc.line(), 14); assert_eq!(loc.column(), 15); // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, // i.e. point to where the macro was invoked, instead of the macro itself. let loc2 = caller_location_from_macro!(); assert_eq!(loc2.file(), file!()); - assert_eq!(loc2.line(), 23); + assert_eq!(loc2.line(), 21); assert_eq!(loc2.column(), 16); } diff --git a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs index 0614c52c66036..8030a4d967a67 100644 --- a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs +++ b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(const_fn, track_caller)] +#![feature(const_caller_location, const_fn)] use std::panic::Location; diff --git a/src/test/ui/rfc-2091-track-caller/diverging-caller-location.rs b/src/test/ui/rfc-2091-track-caller/diverging-caller-location.rs index 1fb75ef35ffc1..6681119557d79 100644 --- a/src/test/ui/rfc-2091-track-caller/diverging-caller-location.rs +++ b/src/test/ui/rfc-2091-track-caller/diverging-caller-location.rs @@ -6,8 +6,6 @@ //! we don't inspect the location returned -- it would be difficult to distinguish between the //! explicit panic and a failed assertion. That it compiles and runs is enough for this one. -#![feature(track_caller)] - #[track_caller] fn doesnt_return() -> ! { let _location = core::panic::Location::caller(); diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs index d6560231871c9..6f4290e2a5ee9 100644 --- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs +++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs @@ -1,5 +1,3 @@ -#![feature(track_caller)] - #[track_caller(1)] fn f() {} //~^^ ERROR malformed `track_caller` attribute input diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr index 8906fa59506a7..e7ddf8df4ab53 100644 --- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr @@ -1,5 +1,5 @@ error: malformed `track_caller` attribute input - --> $DIR/error-odd-syntax.rs:3:1 + --> $DIR/error-odd-syntax.rs:1:1 | LL | #[track_caller(1)] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]` diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs index 1145f7786c78b..074e1ceb791ce 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -1,5 +1,3 @@ -#![feature(track_caller)] - #[track_caller] extern "C" fn f() {} //~^^ ERROR `#[track_caller]` requires Rust ABI diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr index e08c52fabd6b7..bcc0c8170e655 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -1,11 +1,11 @@ error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/error-with-invalid-abi.rs:3:1 + --> $DIR/error-with-invalid-abi.rs:1:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/error-with-invalid-abi.rs:8:5 + --> $DIR/error-with-invalid-abi.rs:6:5 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs index f457384833335..2b110c9a32515 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs @@ -1,4 +1,4 @@ -#![feature(naked_functions, track_caller)] +#![feature(naked_functions)] #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` #[naked] diff --git a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs index 76e62b89ab818..74217f47084a3 100644 --- a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs +++ b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(track_caller)] - macro_rules! caller_location_from_macro { () => (core::panic::Location::caller()); } @@ -9,13 +7,13 @@ macro_rules! caller_location_from_macro { fn main() { let loc = core::panic::Location::caller(); assert_eq!(loc.file(), file!()); - assert_eq!(loc.line(), 10); + assert_eq!(loc.line(), 8); assert_eq!(loc.column(), 15); // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, // i.e. point to where the macro was invoked, instead of the macro itself. let loc2 = caller_location_from_macro!(); assert_eq!(loc2.file(), file!()); - assert_eq!(loc2.line(), 17); + assert_eq!(loc2.line(), 15); assert_eq!(loc2.column(), 16); } diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs index 0fd59b4bf4918..bc0ca9552806f 100644 --- a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs @@ -1,5 +1,3 @@ -#![feature(track_caller)] - #[track_caller] struct S; //~^^ ERROR attribute should be applied to function diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr index c2fb8fa1eb6ca..6666dcfa6e599 100644 --- a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr @@ -1,5 +1,5 @@ error[E0739]: attribute should be applied to function - --> $DIR/only-for-fns.rs:3:1 + --> $DIR/only-for-fns.rs:1:1 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ diff --git a/src/test/ui/rfc-2091-track-caller/pass.rs b/src/test/ui/rfc-2091-track-caller/pass.rs index eef83b3d68f97..ada150b25cf2c 100644 --- a/src/test/ui/rfc-2091-track-caller/pass.rs +++ b/src/test/ui/rfc-2091-track-caller/pass.rs @@ -1,6 +1,4 @@ // run-pass -#![feature(track_caller)] - #[track_caller] fn f() {} diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs index 76a380ed3e30d..efcc1f6942de1 100644 --- a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs +++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(track_caller)] - use std::panic::Location; #[track_caller] @@ -20,21 +18,21 @@ fn nested_tracked() -> &'static Location<'static> { fn main() { let location = Location::caller(); assert_eq!(location.file(), file!()); - assert_eq!(location.line(), 21); + assert_eq!(location.line(), 19); assert_eq!(location.column(), 20); let tracked = tracked(); assert_eq!(tracked.file(), file!()); - assert_eq!(tracked.line(), 26); + assert_eq!(tracked.line(), 24); assert_eq!(tracked.column(), 19); let nested = nested_intrinsic(); assert_eq!(nested.file(), file!()); - assert_eq!(nested.line(), 13); + assert_eq!(nested.line(), 11); assert_eq!(nested.column(), 5); let contained = nested_tracked(); assert_eq!(contained.file(), file!()); - assert_eq!(contained.line(), 17); + assert_eq!(contained.line(), 15); assert_eq!(contained.column(), 5); } diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-ffi.rs b/src/test/ui/rfc-2091-track-caller/track-caller-ffi.rs index 23c17d743c43c..5115f687c2632 100644 --- a/src/test/ui/rfc-2091-track-caller/track-caller-ffi.rs +++ b/src/test/ui/rfc-2091-track-caller/track-caller-ffi.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(track_caller)] - use std::panic::Location; extern "Rust" { @@ -30,21 +28,21 @@ mod provides { fn main() { let location = Location::caller(); assert_eq!(location.file(), file!()); - assert_eq!(location.line(), 31); + assert_eq!(location.line(), 29); assert_eq!(location.column(), 20); let tracked = unsafe { rust_track_caller_ffi_test_tracked() }; assert_eq!(tracked.file(), file!()); - assert_eq!(tracked.line(), 36); + assert_eq!(tracked.line(), 34); assert_eq!(tracked.column(), 28); let untracked = unsafe { rust_track_caller_ffi_test_untracked() }; assert_eq!(untracked.file(), file!()); - assert_eq!(untracked.line(), 26); + assert_eq!(untracked.line(), 24); assert_eq!(untracked.column(), 9); let contained = rust_track_caller_ffi_test_nested_tracked(); assert_eq!(contained.file(), file!()); - assert_eq!(contained.line(), 14); + assert_eq!(contained.line(), 12); assert_eq!(contained.column(), 14); } diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs index b17c1efb3d38c..5fcfea96d547a 100644 --- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs +++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr-with-arg.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(track_caller)] - fn pass_to_ptr_call(f: fn(T), x: T) { f(x); } diff --git a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs index 8ee4d4fa16871..4415d850c241c 100644 --- a/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs +++ b/src/test/ui/rfc-2091-track-caller/tracked-fn-ptr.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(track_caller)] - fn ptr_call(f: fn()) { f(); } diff --git a/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs b/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs index 0a5f92bb635e5..4db4c29e53d58 100644 --- a/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs +++ b/src/test/ui/rfc-2091-track-caller/tracked-trait-impls.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(track_caller)] - macro_rules! assert_expansion_site_is_tracked { () => {{ let location = std::panic::Location::caller(); From a5764de00b8d953a4071c9318a31628fa0549982 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 14 Jun 2020 14:30:42 +0300 Subject: [PATCH 79/92] expand: Stop using nonterminals for passing tokens to attribute and derive macros --- src/librustc_ast/token.rs | 22 ++++++++- src/librustc_ast_pretty/pprust.rs | 18 +++++-- src/librustc_expand/base.rs | 13 ++--- src/librustc_expand/expand.rs | 2 +- src/librustc_expand/proc_macro.rs | 12 +++-- src/librustc_expand/proc_macro_server.rs | 8 +++- src/librustc_span/symbol.rs | 3 ++ .../run-make/rustc-macro-dep-files/foo.rs | 2 +- .../ui/async-await/issues/issue-60674.stdout | 6 +-- src/test/ui/proc-macro/auxiliary/attr-cfg.rs | 8 ++-- .../auxiliary/attr-stmt-expr-rpass.rs | 6 +-- .../ui/proc-macro/auxiliary/attr-stmt-expr.rs | 6 +-- src/test/ui/proc-macro/auxiliary/derive-a.rs | 2 +- .../ui/proc-macro/auxiliary/derive-atob.rs | 2 +- .../ui/proc-macro/auxiliary/derive-b-rpass.rs | 2 +- .../ui/proc-macro/auxiliary/derive-ctod.rs | 2 +- .../auxiliary/derive-same-struct.rs | 4 +- .../ui/proc-macro/auxiliary/derive-union.rs | 2 +- src/test/ui/proc-macro/auxiliary/double.rs | 7 +-- .../auxiliary/expand-with-a-macro.rs | 2 +- .../ui/proc-macro/derive-same-struct.stdout | 2 +- .../dollar-crate-issue-57089.stdout | 3 +- .../dollar-crate-issue-62325.stdout | 6 +-- src/test/ui/proc-macro/dollar-crate.stdout | 12 ++--- .../ui/proc-macro/input-interpolated.stdout | 7 +-- .../auxiliary/param-attrs.rs | 47 +++++++++---------- 26 files changed, 118 insertions(+), 88 deletions(-) diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index 89be3e6e212cc..34b8e6a285cd5 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -11,7 +11,7 @@ use crate::tokenstream::TokenTree; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable_Generic; -use rustc_span::symbol::kw; +use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, Span, DUMMY_SP}; use std::borrow::Cow; @@ -785,6 +785,26 @@ impl Nonterminal { NtTT(tt) => tt.span(), } } + + /// This nonterminal looks like some specific enums from + /// `proc-macro-hack` and `procedural-masquerade` crates. + /// We need to maintain some special pretty-printing behavior for them due to incorrect + /// asserts in old versions of those crates and their wide use in the ecosystem. + /// See issue #73345 for more details. + /// FIXME: Remove this eventually. + pub fn pretty_printing_compatibility_hack(&self) -> bool { + if let NtItem(item) = self { + let name = item.ident.name; + if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack { + if let ast::ItemKind::Enum(enum_def, _) = &item.kind { + if let [variant] = &*enum_def.variants { + return variant.ident.name == sym::Input; + } + } + } + } + false + } } impl PartialEq for Nonterminal { diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 86faa1f086ce2..4740b2d9cce81 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -148,9 +148,14 @@ pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { printer.s.eof() } -// This makes comma-separated lists look slightly nicer, -// and also addresses a specific regression described in issue #63896. +// This makes printed token streams look slightly nicer, +// and also addresses some specific regressions described in #63896 and #73345. fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { + if let TokenTree::Token(token) = prev { + if let token::DocComment(s) = token.kind { + return !s.as_str().starts_with("//"); + } + } match tt { TokenTree::Token(token) => match token.kind { token::Comma => false, @@ -163,7 +168,14 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { }, _ => true, }, - _ => true, + TokenTree::Delimited(_, DelimToken::Bracket, _) => match prev { + TokenTree::Token(token) => match token.kind { + token::Pound => false, + _ => true, + }, + _ => true, + }, + TokenTree::Delimited(..) => true, } } diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 757eee8bb46e1..82f199be6c62d 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -4,14 +4,14 @@ use crate::module::DirectoryOwnership; use rustc_ast::ast::{self, Attribute, NodeId, PatKind}; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, FlattenGroup}; -use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; +use rustc_ast::token; +use rustc_ast::tokenstream::{self, TokenStream}; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagnosticBuilder, ErrorReported}; -use rustc_parse::{self, parser, MACRO_ARGUMENTS}; +use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS}; use rustc_session::{parse::ParseSess, Limit}; use rustc_span::def_id::DefId; use rustc_span::edition::Edition; @@ -120,10 +120,7 @@ impl Annotatable { } } - crate fn into_tokens(self) -> TokenStream { - // `Annotatable` can be converted into tokens directly, but we - // are packing it into a nonterminal as a piece of AST to make - // the produced token stream look nicer in pretty-printed form. + crate fn into_tokens(self, sess: &ParseSess) -> TokenStream { let nt = match self { Annotatable::Item(item) => token::NtItem(item), Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => { @@ -142,7 +139,7 @@ impl Annotatable { | Annotatable::StructField(..) | Annotatable::Variant(..) => panic!("unexpected annotatable"), }; - TokenTree::token(token::Interpolated(Lrc::new(nt), FlattenGroup::Yes), DUMMY_SP).into() + nt_to_tokenstream(&nt, sess, DUMMY_SP) } pub fn expect_item(self) -> P { diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 4e41bd4bbfa08..bd7a094c5e355 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -705,7 +705,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); - let tokens = item.into_tokens(); + let tokens = item.into_tokens(self.cx.parse_sess); let attr_item = attr.unwrap_normal_item(); if let MacArgs::Eq(..) = attr_item.args { self.cx.span_err(span, "key-value macro attributes are not supported"); diff --git a/src/librustc_expand/proc_macro.rs b/src/librustc_expand/proc_macro.rs index 1e26c832a2621..8fae64161e7fd 100644 --- a/src/librustc_expand/proc_macro.rs +++ b/src/librustc_expand/proc_macro.rs @@ -3,9 +3,10 @@ use crate::proc_macro_server; use rustc_ast::ast::{self, ItemKind, MetaItemKind, NestedMetaItem}; use rustc_ast::token::{self, FlattenGroup}; -use rustc_ast::tokenstream::{self, TokenStream}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, ErrorReported}; +use rustc_parse::nt_to_tokenstream; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -102,8 +103,13 @@ impl MultiItemModifier for ProcMacroDerive { } } - let token = token::Interpolated(Lrc::new(token::NtItem(item)), FlattenGroup::Yes); - let input = tokenstream::TokenTree::token(token, DUMMY_SP).into(); + let item = token::NtItem(item); + let input = if item.pretty_printing_compatibility_hack() { + TokenTree::token(token::Interpolated(Lrc::new(item), FlattenGroup::Yes), DUMMY_SP) + .into() + } else { + nt_to_tokenstream(&item, ecx.parse_sess, DUMMY_SP) + }; let server = proc_macro_server::Rustc::new(ecx); let stream = match self.client.run(&EXEC_STRATEGY, server, input) { diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index c88b5a37f718a..29f954b41b504 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -180,13 +180,17 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> tt!(Punct::new('#', false)) } - Interpolated(nt, flatten) => { + Interpolated(nt, _) => { let stream = nt_to_tokenstream(&nt, sess, span); TokenTree::Group(Group { delimiter: Delimiter::None, stream, span: DelimSpan::from_single(span), - flatten, + flatten: if nt.pretty_printing_compatibility_hack() { + FlattenGroup::Yes + } else { + FlattenGroup::No + }, }) } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 857734037afe7..9b51d5dccb4a3 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -401,6 +401,7 @@ symbols! { infer_outlives_requirements, infer_static_outlives_requirements, inline, + Input, intel, into_iter, IntoIterator, @@ -588,6 +589,8 @@ symbols! { proc_macro_mod, proc_macro_non_items, proc_macro_path_invoc, + ProceduralMasqueradeDummyType, + ProcMacroHack, profiler_builtins, profiler_runtime, ptr_guaranteed_eq, diff --git a/src/test/run-make/rustc-macro-dep-files/foo.rs b/src/test/run-make/rustc-macro-dep-files/foo.rs index 00b1c26d43f10..66db1a2173665 100644 --- a/src/test/run-make/rustc-macro-dep-files/foo.rs +++ b/src/test/run-make/rustc-macro-dep-files/foo.rs @@ -7,6 +7,6 @@ use proc_macro::TokenStream; #[proc_macro_derive(A)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert!(input.contains("struct A;")); + assert!(input.contains("struct A ;")); "struct B;".parse().unwrap() } diff --git a/src/test/ui/async-await/issues/issue-60674.stdout b/src/test/ui/async-await/issues/issue-60674.stdout index 86c3591b3afc0..395d9e21b3848 100644 --- a/src/test/ui/async-await/issues/issue-60674.stdout +++ b/src/test/ui/async-await/issues/issue-60674.stdout @@ -1,3 +1,3 @@ -async fn f(mut x: u8) { } -async fn g((mut x, y, mut z): (u8, u8, u8)) { } -async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) { } +async fn f(mut x : u8) { } +async fn g((mut x, y, mut z) : (u8, u8, u8)) { } +async fn g(mut x : u8, (a, mut b, c) : (u8, u8, u8), y : u8) { } diff --git a/src/test/ui/proc-macro/auxiliary/attr-cfg.rs b/src/test/ui/proc-macro/auxiliary/attr-cfg.rs index f50e18d7be30e..2f0054cc14aa6 100644 --- a/src/test/ui/proc-macro/auxiliary/attr-cfg.rs +++ b/src/test/ui/proc-macro/auxiliary/attr-cfg.rs @@ -11,11 +11,9 @@ use proc_macro::TokenStream; pub fn attr_cfg(args: TokenStream, input: TokenStream) -> TokenStream { let input_str = input.to_string(); - assert_eq!(input_str, "fn outer() -> u8 { - #[cfg(foo)] - fn inner() -> u8 { 1 } - #[cfg(bar)] - fn inner() -> u8 { 2 } + assert_eq!(input_str, "fn outer() -> u8 +{ + #[cfg(foo)] fn inner() -> u8 { 1 } #[cfg(bar)] fn inner() -> u8 { 2 } inner() }"); diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs index f1de3709b166b..e056bd32d2d0e 100644 --- a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs +++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr-rpass.rs @@ -10,14 +10,14 @@ use proc_macro::TokenStream; #[proc_macro_attribute] pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "let string = \"Hello, world!\";"); + assert_eq!(item.to_string(), "let string = \"Hello, world!\" ;"); item } #[proc_macro_attribute] pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\", string);"); + assert_eq!(item.to_string(), "println ! (\"{}\", string) ;"); item } @@ -31,7 +31,7 @@ pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\", string)"); + assert_eq!(item.to_string(), "println ! (\"{}\", string)"); item } diff --git a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs index d2180def5b760..213f999e9d0ea 100644 --- a/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs +++ b/src/test/ui/proc-macro/auxiliary/attr-stmt-expr.rs @@ -10,14 +10,14 @@ use proc_macro::TokenStream; #[proc_macro_attribute] pub fn expect_let(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "let string = \"Hello, world!\";"); + assert_eq!(item.to_string(), "let string = \"Hello, world!\" ;"); item } #[proc_macro_attribute] pub fn expect_print_stmt(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\", string);"); + assert_eq!(item.to_string(), "println ! (\"{}\", string) ;"); item } @@ -31,7 +31,7 @@ pub fn expect_expr(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn expect_print_expr(attr: TokenStream, item: TokenStream) -> TokenStream { assert!(attr.to_string().is_empty()); - assert_eq!(item.to_string(), "println!(\"{}\", string)"); + assert_eq!(item.to_string(), "println ! (\"{}\", string)"); item } diff --git a/src/test/ui/proc-macro/auxiliary/derive-a.rs b/src/test/ui/proc-macro/auxiliary/derive-a.rs index cd2be5fd84d44..79a3864bf991d 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-a.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-a.rs @@ -10,6 +10,6 @@ use proc_macro::TokenStream; #[proc_macro_derive(A)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert!(input.contains("struct A;")); + assert!(input.contains("struct A ;")); "".parse().unwrap() } diff --git a/src/test/ui/proc-macro/auxiliary/derive-atob.rs b/src/test/ui/proc-macro/auxiliary/derive-atob.rs index e78e5bb8f4c75..207b7fd320360 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-atob.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-atob.rs @@ -10,6 +10,6 @@ use proc_macro::TokenStream; #[proc_macro_derive(AToB)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert_eq!(input, "struct A;"); + assert_eq!(input, "struct A ;"); "struct B;".parse().unwrap() } diff --git a/src/test/ui/proc-macro/auxiliary/derive-b-rpass.rs b/src/test/ui/proc-macro/auxiliary/derive-b-rpass.rs index 3e6af67a9f412..641a95f78c112 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-b-rpass.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-b-rpass.rs @@ -10,7 +10,7 @@ use proc_macro::TokenStream; #[proc_macro_derive(B, attributes(B, C))] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert!(input.contains("#[B[arbitrary tokens]]")); + assert!(input.contains("#[B [arbitrary tokens]]")); assert!(input.contains("struct B {")); assert!(input.contains("#[C]")); "".parse().unwrap() diff --git a/src/test/ui/proc-macro/auxiliary/derive-ctod.rs b/src/test/ui/proc-macro/auxiliary/derive-ctod.rs index dbf44ed1b0537..2efe5a9134054 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-ctod.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-ctod.rs @@ -10,6 +10,6 @@ use proc_macro::TokenStream; #[proc_macro_derive(CToD)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert_eq!(input, "struct C;"); + assert_eq!(input, "struct C ;"); "struct D;".parse().unwrap() } diff --git a/src/test/ui/proc-macro/auxiliary/derive-same-struct.rs b/src/test/ui/proc-macro/auxiliary/derive-same-struct.rs index ce7a50d2381cd..7598d632cb6d5 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-same-struct.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-same-struct.rs @@ -10,12 +10,12 @@ use proc_macro::TokenStream; #[proc_macro_derive(AToB)] pub fn derive1(input: TokenStream) -> TokenStream { println!("input1: {:?}", input.to_string()); - assert_eq!(input.to_string(), "struct A;"); + assert_eq!(input.to_string(), "struct A ;"); "#[derive(BToC)] struct B;".parse().unwrap() } #[proc_macro_derive(BToC)] pub fn derive2(input: TokenStream) -> TokenStream { - assert_eq!(input.to_string(), "struct B;"); + assert_eq!(input.to_string(), "struct B ;"); "struct C;".parse().unwrap() } diff --git a/src/test/ui/proc-macro/auxiliary/derive-union.rs b/src/test/ui/proc-macro/auxiliary/derive-union.rs index d950e1e773c70..05883170c6c48 100644 --- a/src/test/ui/proc-macro/auxiliary/derive-union.rs +++ b/src/test/ui/proc-macro/auxiliary/derive-union.rs @@ -12,7 +12,7 @@ pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); assert!(input.contains("#[repr(C)]")); assert!(input.contains("union Test {")); - assert!(input.contains("a: u8,")); + assert!(input.contains("a : u8,")); assert!(input.contains("}")); "".parse().unwrap() } diff --git a/src/test/ui/proc-macro/auxiliary/double.rs b/src/test/ui/proc-macro/auxiliary/double.rs index 3a2e8d04c36b5..99eb4e3754672 100644 --- a/src/test/ui/proc-macro/auxiliary/double.rs +++ b/src/test/ui/proc-macro/auxiliary/double.rs @@ -1,15 +1,16 @@ // force-host // no-prefer-dynamic +#![feature(proc_macro_quote)] + #![crate_type = "proc-macro"] extern crate proc_macro; - -use proc_macro::TokenStream; +use proc_macro::*; // Outputs another copy of the struct. Useful for testing the tokens // seen by the proc_macro. #[proc_macro_derive(Double)] pub fn derive(input: TokenStream) -> TokenStream { - format!("mod foo {{ {} }}", input.to_string()).parse().unwrap() + quote!(mod foo { $input }) } diff --git a/src/test/ui/proc-macro/auxiliary/expand-with-a-macro.rs b/src/test/ui/proc-macro/auxiliary/expand-with-a-macro.rs index 5155a4b855865..d779d57af14c7 100644 --- a/src/test/ui/proc-macro/auxiliary/expand-with-a-macro.rs +++ b/src/test/ui/proc-macro/auxiliary/expand-with-a-macro.rs @@ -11,7 +11,7 @@ use proc_macro::TokenStream; #[proc_macro_derive(A)] pub fn derive(input: TokenStream) -> TokenStream { let input = input.to_string(); - assert!(input.contains("struct A;")); + assert!(input.contains("struct A ;")); r#" impl A { fn a(&self) { diff --git a/src/test/ui/proc-macro/derive-same-struct.stdout b/src/test/ui/proc-macro/derive-same-struct.stdout index 77605de5e33fc..7478d9741409b 100644 --- a/src/test/ui/proc-macro/derive-same-struct.stdout +++ b/src/test/ui/proc-macro/derive-same-struct.stdout @@ -1 +1 @@ -input1: "struct A;" +input1: "struct A ;" diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout index 15433bebde967..5d93144b44553 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -38,8 +38,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: #3 bytes(LO..HI), }, ] -PRINT-ATTR INPUT (DISPLAY): struct A(crate::S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; +PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout index 73e407918ec8c..e4212377626ca 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout @@ -1,5 +1,4 @@ -PRINT-ATTR INPUT (DISPLAY): struct A(identity!(crate :: S)); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A(identity ! ($crate :: S)) ; +PRINT-ATTR INPUT (DISPLAY): struct A(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -54,8 +53,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #3 bytes(LO..HI), }, ] -PRINT-ATTR INPUT (DISPLAY): struct B(identity!(::dollar_crate_external :: S)); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct B(identity ! ($crate :: S)) ; +PRINT-ATTR INPUT (DISPLAY): struct B(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index e125a3e7f1737..8a7406b1a3d13 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -38,8 +38,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: #3 bytes(LO..HI), }, ] -PRINT-ATTR INPUT (DISPLAY): struct A(crate::S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; +PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -79,8 +78,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #3 bytes(LO..HI), }, ] -PRINT-DERIVE INPUT (DISPLAY): struct D(crate::S); -PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D($crate :: S) ; +PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -160,8 +158,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: #13 bytes(LO..HI), }, ] -PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S); -PRINT-ATTR RE-COLLECTED (DISPLAY): struct A($crate :: S) ; +PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", @@ -201,8 +198,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #13 bytes(LO..HI), }, ] -PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S); -PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D($crate :: S) ; +PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/src/test/ui/proc-macro/input-interpolated.stdout b/src/test/ui/proc-macro/input-interpolated.stdout index 7529db3bd06f8..72e40b8a33e0b 100644 --- a/src/test/ui/proc-macro/input-interpolated.stdout +++ b/src/test/ui/proc-macro/input-interpolated.stdout @@ -12,8 +12,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: #3 bytes(269..271), }, ] -PRINT-ATTR INPUT (DISPLAY): const A: u8 = 0; -PRINT-ATTR RE-COLLECTED (DISPLAY): const A : u8 = 0 ; +PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "const", @@ -49,9 +48,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #0 bytes(0..0), }, ] -PRINT-DERIVE INPUT (DISPLAY): struct A { -} -PRINT-DERIVE RE-COLLECTED (DISPLAY): struct A { } +PRINT-DERIVE INPUT (DISPLAY): struct A { } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", diff --git a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs index c537c1034b5a6..2a172c8458d71 100644 --- a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs +++ b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs @@ -17,28 +17,27 @@ macro_rules! checker { } } -checker!(attr_extern, r#"extern "C" { - fn ffi(#[a1] arg1: i32, #[a2] ...); -}"#); -checker!(attr_extern_cvar, r#"unsafe extern "C" fn cvar(arg1: i32, #[a1] mut args: ...) { }"#); -checker!(attr_alias, "type Alias = fn(#[a1] u8, #[a2] ...);"); -checker!(attr_free, "fn free(#[a1] arg1: u8) { let lam = |#[a2] W(x), #[a3] y| (); }"); -checker!(attr_inherent_1, "fn inherent1(#[a1] self, #[a2] arg1: u8) { }"); -checker!(attr_inherent_2, "fn inherent2(#[a1] &self, #[a2] arg1: u8) { }"); -checker!(attr_inherent_3, "fn inherent3<'a>(#[a1] &'a mut self, #[a2] arg1: u8) { }"); -checker!(attr_inherent_4, "fn inherent4<'a>(#[a1] self: Box, #[a2] arg1: u8) { }"); -checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8) { }"); -checker!(attr_trait_1, "fn trait1(#[a1] self, #[a2] arg1: u8);"); -checker!(attr_trait_2, "fn trait2(#[a1] &self, #[a2] arg1: u8);"); -checker!(attr_trait_3, "fn trait3<'a>(#[a1] &'a mut self, #[a2] arg1: u8);"); -checker!(attr_trait_4, "fn trait4<'a>(#[a1] self: Box, #[a2] arg1: u8, #[a3] Vec);"); -checker!(attr_trait_issue_64682, "fn trait5(#[a1] #[a2] arg1: u8, #[a3] arg2: u8);"); -checker!(rename_params, r#"impl Foo { - fn hello(#[angery(true)] a: i32, #[a2] b: i32, #[what = "how"] c: u32) { } - fn hello2(#[a1] #[a2] a: i32, #[what = "how"] b: i32, - #[angery(true)] c: u32) { - } - fn hello_self(#[a1] #[a2] &self, #[a1] #[a2] a: i32, - #[what = "how"] b: i32, #[angery(true)] c: u32) { - } +checker!(attr_extern, r#"extern "C" { fn ffi(#[a1] arg1 : i32, #[a2] ...) ; }"#); +checker!(attr_extern_cvar, r#"unsafe extern "C" fn cvar(arg1 : i32, #[a1] mut args : ...) { }"#); +checker!(attr_alias, "type Alias = fn(#[a1] u8, #[a2] ...) ;"); +checker!(attr_free, "fn free(#[a1] arg1 : u8) { let lam = | #[a2] W(x), #[a3] y | () ; }"); +checker!(attr_inherent_1, "fn inherent1(#[a1] self, #[a2] arg1 : u8) { }"); +checker!(attr_inherent_2, "fn inherent2(#[a1] & self, #[a2] arg1 : u8) { }"); +checker!(attr_inherent_3, "fn inherent3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) { }"); +checker!(attr_inherent_4, "fn inherent4 < 'a > (#[a1] self : Box < Self >, #[a2] arg1 : u8) { }"); +checker!(attr_inherent_issue_64682, "fn inherent5(#[a1] #[a2] arg1 : u8, #[a3] arg2 : u8) { }"); +checker!(attr_trait_1, "fn trait1(#[a1] self, #[a2] arg1 : u8) ;"); +checker!(attr_trait_2, "fn trait2(#[a1] & self, #[a2] arg1 : u8) ;"); +checker!(attr_trait_3, "fn trait3 < 'a > (#[a1] & 'a mut self, #[a2] arg1 : u8) ;"); +checker!(attr_trait_4, r#"fn trait4 < 'a > +(#[a1] self : Box < Self >, #[a2] arg1 : u8, #[a3] Vec < u8 >) ;"#); +checker!(attr_trait_issue_64682, "fn trait5(#[a1] #[a2] arg1 : u8, #[a3] arg2 : u8) ;"); +checker!(rename_params, r#"impl Foo +{ + fn hello(#[angery(true)] a : i32, #[a2] b : i32, #[what = "how"] c : u32) + { } fn + hello2(#[a1] #[a2] a : i32, #[what = "how"] b : i32, #[angery(true)] c : + u32) { } fn + hello_self(#[a1] #[a2] & self, #[a1] #[a2] a : i32, #[what = "how"] b : + i32, #[angery(true)] c : u32) { } }"#); From b37434ef31bb896b473a1eb67b8f191c04b2c9f3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 1 Jul 2020 13:16:49 +0300 Subject: [PATCH 80/92] Remove `token::FlattenGroup` --- src/librustc_ast/attr/mod.rs | 2 +- src/librustc_ast/mut_visit.rs | 2 +- src/librustc_ast/token.rs | 29 +++++++-------------- src/librustc_ast/util/literal.rs | 2 +- src/librustc_ast_lowering/lib.rs | 2 +- src/librustc_ast_pretty/pprust.rs | 2 +- src/librustc_expand/base.rs | 2 +- src/librustc_expand/mbe/macro_parser.rs | 8 +++--- src/librustc_expand/mbe/transcribe.rs | 7 ++--- src/librustc_expand/proc_macro.rs | 5 ++-- src/librustc_expand/proc_macro_server.rs | 25 ++++++------------ src/librustc_parse/parser/attr.rs | 4 +-- src/librustc_parse/parser/expr.rs | 2 +- src/librustc_parse/parser/item.rs | 2 +- src/librustc_parse/parser/mod.rs | 6 ++--- src/librustc_parse/parser/pat.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/def_collector.rs | 2 +- 18 files changed, 42 insertions(+), 64 deletions(-) diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index 6c128f0176f66..b812f2dadf6d4 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -475,7 +475,7 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments } } - Some(TokenTree::Token(Token { kind: token::Interpolated(nt, _), .. })) => match *nt { + Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), token::Nonterminal::NtPath(ref path) => path.clone(), _ => return None, diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index 3fd2815daa14f..54f81ef106fe1 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -656,7 +656,7 @@ pub fn noop_visit_token(t: &mut Token, vis: &mut T) { *span = ident.span; return; // Avoid visiting the span for the second time. } - token::Interpolated(nt, _) => { + token::Interpolated(nt) => { let mut nt = Lrc::make_mut(nt); vis.visit_interpolated(&mut nt); } diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index 34b8e6a285cd5..0f0428574de0f 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -182,15 +182,6 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool { .contains(&name) } -/// A hack used to pass AST fragments to attribute and derive macros -/// as a single nonterminal token instead of a token stream. -/// FIXME: It needs to be removed, but there are some compatibility issues (see #73345). -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] -pub enum FlattenGroup { - Yes, - No, -} - #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum TokenKind { /* Expression-operator symbols. */ @@ -245,7 +236,7 @@ pub enum TokenKind { /// treat regular and interpolated lifetime identifiers in the same way. Lifetime(Symbol), - Interpolated(Lrc, FlattenGroup), + Interpolated(Lrc), // Can be expanded into several tokens. /// A doc comment. @@ -352,7 +343,7 @@ impl Token { /// if they keep spans or perform edition checks. pub fn uninterpolated_span(&self) -> Span { match &self.kind { - Interpolated(nt, _) => nt.span(), + Interpolated(nt) => nt.span(), _ => self.span, } } @@ -391,7 +382,7 @@ impl Token { ModSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt, _) => match **nt { + Interpolated(ref nt) => match **nt { NtLiteral(..) | NtExpr(..) | NtBlock(..) | @@ -417,7 +408,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path ModSep => true, // global path - Interpolated(ref nt, _) => match **nt { + Interpolated(ref nt) => match **nt { NtTy(..) | NtPath(..) => true, _ => false, }, @@ -429,7 +420,7 @@ impl Token { pub fn can_begin_const_arg(&self) -> bool { match self.kind { OpenDelim(Brace) => true, - Interpolated(ref nt, _) => match **nt { + Interpolated(ref nt) => match **nt { NtExpr(..) | NtBlock(..) | NtLiteral(..) => true, _ => false, }, @@ -464,7 +455,7 @@ impl Token { match self.uninterpolate().kind { Literal(..) | BinOp(Minus) => true, Ident(name, false) if name.is_bool_lit() => true, - Interpolated(ref nt, _) => match &**nt { + Interpolated(ref nt) => match &**nt { NtLiteral(_) => true, NtExpr(e) => match &e.kind { ast::ExprKind::Lit(_) => true, @@ -485,7 +476,7 @@ impl Token { // otherwise returns the original token. pub fn uninterpolate(&self) -> Cow<'_, Token> { match &self.kind { - Interpolated(nt, _) => match **nt { + Interpolated(nt) => match **nt { NtIdent(ident, is_raw) => { Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)) } @@ -532,7 +523,7 @@ impl Token { /// Returns `true` if the token is an interpolated path. fn is_path(&self) -> bool { - if let Interpolated(ref nt, _) = self.kind { + if let Interpolated(ref nt) = self.kind { if let NtPath(..) = **nt { return true; } @@ -544,7 +535,7 @@ impl Token { /// That is, is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { - if let Interpolated(ref nt, _) = self.kind { + if let Interpolated(ref nt) = self.kind { if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt { return true; } @@ -555,7 +546,7 @@ impl Token { // Is the token an interpolated block (`$b:block`)? pub fn is_whole_block(&self) -> bool { - if let Interpolated(ref nt, _) = self.kind { + if let Interpolated(ref nt) = self.kind { if let NtBlock(..) = **nt { return true; } diff --git a/src/librustc_ast/util/literal.rs b/src/librustc_ast/util/literal.rs index ea59f867c59d2..4428d09902b92 100644 --- a/src/librustc_ast/util/literal.rs +++ b/src/librustc_ast/util/literal.rs @@ -205,7 +205,7 @@ impl Lit { token::Lit::new(token::Bool, name, None) } token::Literal(lit) => lit, - token::Interpolated(ref nt, _) => { + token::Interpolated(ref nt) => { if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt { if let ast::ExprKind::Lit(lit) = &expr.kind { return Ok(lit.clone()); diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index bc0980f041b94..0ad74a8e2056a 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1027,7 +1027,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_token(&mut self, token: Token) -> TokenStream { match token.kind { - token::Interpolated(nt, _) => { + token::Interpolated(nt) => { let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span); self.lower_token_stream(tts) } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 4740b2d9cce81..d7e816cec901e 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -278,7 +278,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) token::Shebang(s) => format!("/* shebang: {}*/", s), token::Unknown(s) => s.to_string(), - token::Interpolated(ref nt, _) => nonterminal_to_string(nt), + token::Interpolated(ref nt) => nonterminal_to_string(nt), } } diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index 82f199be6c62d..db9293bddeb7d 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -371,7 +371,7 @@ where impl MutVisitor for AvoidInterpolatedIdents { fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) { if let tokenstream::TokenTree::Token(token) = tt { - if let token::Interpolated(nt, _) = &token.kind { + if let token::Interpolated(nt) = &token.kind { if let token::NtIdent(ident, is_raw) = **nt { *tt = tokenstream::TokenTree::token( token::Ident(ident.name, is_raw), diff --git a/src/librustc_expand/mbe/macro_parser.rs b/src/librustc_expand/mbe/macro_parser.rs index c90a438c25ece..3c15a81c67f67 100644 --- a/src/librustc_expand/mbe/macro_parser.rs +++ b/src/librustc_expand/mbe/macro_parser.rs @@ -790,7 +790,7 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool { }, sym::block => match token.kind { token::OpenDelim(token::Brace) => true, - token::Interpolated(ref nt, _) => match **nt { + token::Interpolated(ref nt) => match **nt { token::NtItem(_) | token::NtPat(_) | token::NtTy(_) @@ -804,7 +804,7 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool { }, sym::path | sym::meta => match token.kind { token::ModSep | token::Ident(..) => true, - token::Interpolated(ref nt, _) => match **nt { + token::Interpolated(ref nt) => match **nt { token::NtPath(_) | token::NtMeta(_) => true, _ => may_be_ident(&nt), }, @@ -823,12 +823,12 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool { token::ModSep | // path token::Lt | // path (UFCS constant) token::BinOp(token::Shl) => true, // path (double UFCS) - token::Interpolated(ref nt, _) => may_be_ident(nt), + token::Interpolated(ref nt) => may_be_ident(nt), _ => false, }, sym::lifetime => match token.kind { token::Lifetime(_) => true, - token::Interpolated(ref nt, _) => match **nt { + token::Interpolated(ref nt) => match **nt { token::NtLifetime(_) | token::NtTT(_) => true, _ => false, }, diff --git a/src/librustc_expand/mbe/transcribe.rs b/src/librustc_expand/mbe/transcribe.rs index 486f0a6420d6e..e2d3d5c4d644e 100644 --- a/src/librustc_expand/mbe/transcribe.rs +++ b/src/librustc_expand/mbe/transcribe.rs @@ -4,7 +4,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use rustc_ast::ast::MacCall; use rustc_ast::mut_visit::{self, MutVisitor}; -use rustc_ast::token::{self, FlattenGroup, NtTT, Token}; +use rustc_ast::token::{self, NtTT, Token}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -240,10 +240,7 @@ pub(super) fn transcribe<'a>( result.push(tt.clone().into()); } else { marker.visit_span(&mut sp); - let token = TokenTree::token( - token::Interpolated(nt.clone(), FlattenGroup::No), - sp, - ); + let token = TokenTree::token(token::Interpolated(nt.clone()), sp); result.push(token.into()); } } else { diff --git a/src/librustc_expand/proc_macro.rs b/src/librustc_expand/proc_macro.rs index 8fae64161e7fd..54012d62a72a7 100644 --- a/src/librustc_expand/proc_macro.rs +++ b/src/librustc_expand/proc_macro.rs @@ -2,7 +2,7 @@ use crate::base::{self, *}; use crate::proc_macro_server; use rustc_ast::ast::{self, ItemKind, MetaItemKind, NestedMetaItem}; -use rustc_ast::token::{self, FlattenGroup}; +use rustc_ast::token; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, ErrorReported}; @@ -105,8 +105,7 @@ impl MultiItemModifier for ProcMacroDerive { let item = token::NtItem(item); let input = if item.pretty_printing_compatibility_hack() { - TokenTree::token(token::Interpolated(Lrc::new(item), FlattenGroup::Yes), DUMMY_SP) - .into() + TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into() } else { nt_to_tokenstream(&item, ecx.parse_sess, DUMMY_SP) }; diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index 29f954b41b504..663bc508143d6 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -1,7 +1,7 @@ use crate::base::ExtCtxt; use rustc_ast::ast; -use rustc_ast::token::{self, FlattenGroup}; +use rustc_ast::token; use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; use rustc_ast::util::comments; use rustc_ast_pretty::pprust; @@ -60,12 +60,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> let Token { kind, span } = match tree { tokenstream::TokenTree::Delimited(span, delim, tts) => { let delimiter = Delimiter::from_internal(delim); - return TokenTree::Group(Group { - delimiter, - stream: tts, - span, - flatten: FlattenGroup::No, - }); + return TokenTree::Group(Group { delimiter, stream: tts, span, flatten: false }); } tokenstream::TokenTree::Token(token) => token, }; @@ -172,7 +167,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> delimiter: Delimiter::Bracket, stream, span: DelimSpan::from_single(span), - flatten: FlattenGroup::No, + flatten: false, })); if style == ast::AttrStyle::Inner { stack.push(tt!(Punct::new('!', false))); @@ -180,17 +175,13 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> tt!(Punct::new('#', false)) } - Interpolated(nt, _) => { + Interpolated(nt) => { let stream = nt_to_tokenstream(&nt, sess, span); TokenTree::Group(Group { delimiter: Delimiter::None, stream, span: DelimSpan::from_single(span), - flatten: if nt.pretty_printing_compatibility_hack() { - FlattenGroup::Yes - } else { - FlattenGroup::No - }, + flatten: nt.pretty_printing_compatibility_hack(), }) } @@ -297,7 +288,7 @@ pub struct Group { /// A hack used to pass AST fragments to attribute and derive macros /// as a single nonterminal token instead of a token stream. /// FIXME: It needs to be removed, but there are some compatibility issues (see #73345). - flatten: FlattenGroup, + flatten: bool, } #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -457,7 +448,7 @@ impl server::TokenStreamIter for Rustc<'_> { // Such token needs to be "unwrapped" and not represented as a delimited group. // FIXME: It needs to be removed, but there are some compatibility issues (see #73345). if let TokenTree::Group(ref group) = tree { - if matches!(group.flatten, FlattenGroup::Yes) { + if group.flatten { iter.cursor.append(group.stream.clone()); continue; } @@ -473,7 +464,7 @@ impl server::Group for Rustc<'_> { delimiter, stream, span: DelimSpan::from_single(server::Span::call_site(self)), - flatten: FlattenGroup::No, + flatten: false, } } fn delimiter(&mut self, group: &Self::Group) -> Delimiter { diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index b8cb146145b98..803f14a2a228a 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -155,7 +155,7 @@ impl<'a> Parser<'a> { /// The delimiters or `=` are still put into the resulting token stream. pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { let item = match self.token.kind { - token::Interpolated(ref nt, _) => match **nt { + token::Interpolated(ref nt) => match **nt { Nonterminal::NtMeta(ref item) => Some(item.clone().into_inner()), _ => None, }, @@ -254,7 +254,7 @@ impl<'a> Parser<'a> { /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { let nt_meta = match self.token.kind { - token::Interpolated(ref nt, _) => match **nt { + token::Interpolated(ref nt) => match **nt { token::NtMeta(ref e) => Some(e.clone()), _ => None, }, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 2745b18a8cd51..49a5c8801766c 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -26,7 +26,7 @@ use std::mem; /// `token::Interpolated` tokens. macro_rules! maybe_whole_expr { ($p:expr) => { - if let token::Interpolated(nt, _) = &$p.token.kind { + if let token::Interpolated(nt) = &$p.token.kind { match &**nt { token::NtExpr(e) | token::NtLiteral(e) => { let e = e.clone(); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 10df16964da08..6f13d7994d17d 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1780,7 +1780,7 @@ impl<'a> Parser<'a> { fn is_named_param(&self) -> bool { let offset = match self.token.kind { - token::Interpolated(ref nt, _) => match **nt { + token::Interpolated(ref nt) => match **nt { token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), _ => 0, }, diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 04074479a21a4..7811d5fb741b2 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -54,7 +54,7 @@ enum BlockMode { #[macro_export] macro_rules! maybe_whole { ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { - if let token::Interpolated(nt, _) = &$p.token.kind { + if let token::Interpolated(nt) = &$p.token.kind { if let token::$constructor(x) = &**nt { let $x = x.clone(); $p.bump(); @@ -69,7 +69,7 @@ macro_rules! maybe_whole { macro_rules! maybe_recover_from_interpolated_ty_qpath { ($self: expr, $allow_qpath_recovery: expr) => { if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) { - if let token::Interpolated(nt, _) = &$self.token.kind { + if let token::Interpolated(nt) = &$self.token.kind { if let token::NtTy(ty) = &**nt { let ty = ty.clone(); $self.bump(); @@ -922,7 +922,7 @@ impl<'a> Parser<'a> { if self.eat(&token::Eq) { let eq_span = self.prev_token.span; let mut is_interpolated_expr = false; - if let token::Interpolated(nt, _) = &self.token.kind { + if let token::Interpolated(nt) = &self.token.kind { if let token::NtExpr(..) = **nt { is_interpolated_expr = true; } diff --git a/src/librustc_parse/parser/pat.rs b/src/librustc_parse/parser/pat.rs index 742183d369735..6603d0afc0248 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/src/librustc_parse/parser/pat.rs @@ -515,7 +515,7 @@ impl<'a> Parser<'a> { self.recover_additional_muts(); // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. - if let token::Interpolated(ref nt, _) = self.token.kind { + if let token::Interpolated(ref nt) = self.token.kind { if let token::NtPat(_) = **nt { self.expected_ident_found().emit(); } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a92d451dfd006..bca65c63e9198 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1325,7 +1325,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { } fn visit_token(&mut self, t: Token) { - if let token::Interpolated(nt, _) = t.kind { + if let token::Interpolated(nt) = t.kind { if let token::NtExpr(ref expr) = *nt { if let ast::ExprKind::MacCall(..) = expr.kind { self.visit_invoc(expr.id); diff --git a/src/librustc_resolve/def_collector.rs b/src/librustc_resolve/def_collector.rs index c25a20210e026..32af920020ce6 100644 --- a/src/librustc_resolve/def_collector.rs +++ b/src/librustc_resolve/def_collector.rs @@ -256,7 +256,7 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { } fn visit_token(&mut self, t: Token) { - if let token::Interpolated(nt, _) = t.kind { + if let token::Interpolated(nt) = t.kind { if let token::NtExpr(ref expr) = *nt { if let ExprKind::MacCall(..) = expr.kind { self.visit_macro_invoc(expr.id); From cd9d8334bd75b33c2c84e6d221621bdfff33e1f3 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 1 Jul 2020 12:36:42 +0000 Subject: [PATCH 81/92] Implement slice_strip feature --- src/libcore/slice/mod.rs | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 6a50cdbc1d9fb..81c1cb295e5d7 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1459,6 +1459,68 @@ impl [T] { m >= n && needle == &self[m - n..] } + /// Returns a subslice with the prefix removed. + /// + /// This method returns [`None`] if slice does not start with `prefix`. + /// Also it returns the original slice if `prefix` is an empty slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..])); + /// assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..])); + /// assert_eq!(v.strip_prefix(&[50]), None); + /// assert_eq!(v.strip_prefix(&[10, 50]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[unstable(feature = "slice_strip", issue = "73413")] + pub fn strip_prefix(&self, prefix: &[T]) -> Option<&[T]> + where + T: PartialEq, + { + let n = prefix.len(); + if n <= self.len() { + let (head, tail) = self.split_at(n); + if head == prefix { + return Some(tail); + } + } + None + } + + /// Returns a subslice with the suffix removed. + /// + /// This method returns [`None`] if slice does not end with `suffix`. + /// Also it returns the original slice if `suffix` is an empty slice + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_strip)] + /// let v = &[10, 40, 30]; + /// assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..])); + /// assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..])); + /// assert_eq!(v.strip_suffix(&[50]), None); + /// assert_eq!(v.strip_suffix(&[50, 30]), None); + /// ``` + #[must_use = "returns the subslice without modifying the original"] + #[unstable(feature = "slice_strip", issue = "73413")] + pub fn strip_suffix(&self, suffix: &[T]) -> Option<&[T]> + where + T: PartialEq, + { + let (len, n) = (self.len(), suffix.len()); + if n <= len { + let (head, tail) = self.split_at(len - n); + if tail == suffix { + return Some(head); + } + } + None + } + /// Binary searches this sorted slice for a given element. /// /// If the value is found then [`Result::Ok`] is returned, containing the From 562e0151d186d82d0d1e0b21aebc8edc20dd17c9 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 9 May 2020 13:26:18 -0400 Subject: [PATCH 82/92] Verify UI tests work in pass=check mode We do not test cross-compilation here as the PR builder lacks a sufficiently recent LLVM to cross-compile to 32-bit linux. Once we bump the minimum LLVM version to LLVM 9, this can use normal 32-bit linux. --- src/ci/docker/x86_64-gnu-llvm-8/Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ci/docker/x86_64-gnu-llvm-8/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-8/Dockerfile index 58fdc6f262376..1d9cad149d9ae 100644 --- a/src/ci/docker/x86_64-gnu-llvm-8/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-8/Dockerfile @@ -45,6 +45,15 @@ ENV SCRIPT python2.7 ../x.py test --exclude src/tools/tidy && \ # (we're only interested in the MIR output, so this doesn't matter) python2.7 ../x.py test src/test/mir-opt --pass=build \ --target=armv5te-unknown-linux-gnueabi && \ + # Run the UI test suite again, but in `--pass=check` mode + # + # This is intended to make sure that both `--pass=check` continues to + # work. + # + # FIXME: We ideally want to test this in 32-bit mode, but currently + # (due to the LLVM problems mentioned above) that isn't readily + # possible. + python2.7 ../x.py test src/test/ui --pass=check && \ # Run tidy at the very end, after all the other tests. python2.7 ../x.py test src/tools/tidy From 9ce1d197ca14c61ff60e4e9ae27cdb9ceb81792c Mon Sep 17 00:00:00 2001 From: "KRAAI, MATTHEW [VISUS]" Date: Wed, 1 Jul 2020 08:35:09 -0700 Subject: [PATCH 83/92] Fix comment typo --- src/bootstrap/builder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 8f0a245a5658a..21ebadb0de4ef 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -980,7 +980,7 @@ impl<'a> Builder<'a> { // we're gated on RUSTC_RPATH here. // // Ok, so the astute might be wondering "why isn't `-C rpath` used - // here?" and that is indeed a good question to task. This codegen + // here?" and that is indeed a good question to ask. This codegen // option is the compiler's current interface to generating an rpath. // Unfortunately it doesn't quite suffice for us. The flag currently // takes no value as an argument, so the compiler calculates what it From 4fd1c77a24288383600b02a7e3f11bf5eb718a32 Mon Sep 17 00:00:00 2001 From: aspen Date: Wed, 1 Jul 2020 12:15:24 -0400 Subject: [PATCH 84/92] Document the CMake defines. --- src/bootstrap/native.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 8d50dd0a9043b..fe1891f3ddf5f 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -177,9 +177,12 @@ impl Step for Llvm { // Are we compiling for iOS/tvOS? if target.contains("apple") && !target.contains("darwin") { + // These two defines prevent CMake from automatically trying to add a MacOSX sysroot, which leads to a compiler error. cfg.define("CMAKE_OSX_SYSROOT", "/"); cfg.define("CMAKE_OSX_DEPLOYMENT_TARGET", ""); - cfg.define("LLVM_ENABLE_PLUGINS", "OFF"); // Prevent cmake from adding -bundle to CFLAGS automatically. + // Prevent cmake from adding -bundle to CFLAGS automatically, which leads to a compiler error because "-bitcode_bundle" also gets added. + cfg.define("LLVM_ENABLE_PLUGINS", "OFF"); + // Zlib fails to link properly, leading to a compiler error. cfg.define("LLVM_ENABLE_ZLIB", "OFF"); } From 22e8ced9fd3ca7767c1ed479d736358b190bf22d Mon Sep 17 00:00:00 2001 From: aspen Date: Wed, 1 Jul 2020 12:21:48 -0400 Subject: [PATCH 85/92] Also document iphoneos-version-min. --- src/bootstrap/native.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index fe1891f3ddf5f..70c292e229da8 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -423,6 +423,7 @@ fn configure_cmake( if let Some(ref s) = builder.config.llvm_cflags { cflags.push_str(&format!(" {}", s)); } + // Some compiler features used by LLVM (such as thread locals) will not work on a min version below iOS 10. if target.contains("apple-ios") { if target.contains("86-") { cflags.push_str(" -miphonesimulator-version-min=10.0"); From 5da0576d83c91f229a73ff9732f99440567d0567 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 20 Jun 2020 20:59:04 -0400 Subject: [PATCH 86/92] Insert NoDelim groups around nonterminals when lowering macro_rules --- src/librustc_ast/attr/mod.rs | 18 +- src/librustc_ast_lowering/lib.rs | 11 +- src/librustc_expand/mbe/macro_rules.rs | 1 + src/librustc_middle/ty/context.rs | 1 + src/test/ui/macros/doc-comment.rs | 25 +++ .../auxiliary/nested-macro-rules.rs | 15 ++ .../ui/proc-macro/auxiliary/test-macros.rs | 6 + src/test/ui/proc-macro/nested-macro-rules.rs | 20 +++ .../ui/proc-macro/nested-macro-rules.stdout | 27 +++ src/test/ui/proc-macro/nodelim-groups.rs | 19 +++ src/test/ui/proc-macro/nodelim-groups.stdout | 156 ++++++++++++++++++ src/test/ui/unsafe/ranged_ints_macro.rs | 16 ++ 12 files changed, 308 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/macros/doc-comment.rs create mode 100644 src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs create mode 100644 src/test/ui/proc-macro/nested-macro-rules.rs create mode 100644 src/test/ui/proc-macro/nested-macro-rules.stdout create mode 100644 src/test/ui/proc-macro/nodelim-groups.rs create mode 100644 src/test/ui/proc-macro/nodelim-groups.stdout create mode 100644 src/test/ui/unsafe/ranged_ints_macro.rs diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index 6c128f0176f66..2dbfe90318ede 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -560,6 +560,9 @@ impl MetaItemKind { tokens: &mut impl Iterator, ) -> Option { match tokens.next() { + Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => { + MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees()) + } Some(TokenTree::Token(token)) => { Lit::from_token(&token).ok().map(MetaItemKind::NameValue) } @@ -619,13 +622,20 @@ impl NestedMetaItem { where I: Iterator, { - if let Some(TokenTree::Token(token)) = tokens.peek() { - if let Ok(lit) = Lit::from_token(token) { + match tokens.peek() { + Some(TokenTree::Token(token)) => { + if let Ok(lit) = Lit::from_token(token) { + tokens.next(); + return Some(NestedMetaItem::Literal(lit)); + } + } + Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => { + let inner_tokens = inner_tokens.clone(); tokens.next(); - return Some(NestedMetaItem::Literal(lit)); + return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable()); } + _ => {} } - MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem) } } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index bc0980f041b94..433dcea9b6ccd 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -39,8 +39,8 @@ use rustc_ast::ast; use rustc_ast::ast::*; use rustc_ast::attr; use rustc_ast::node_id::NodeMap; -use rustc_ast::token::{self, Nonterminal, Token}; -use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::token::{self, DelimToken, Nonterminal, Token}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::walk_list; use rustc_ast_pretty::pprust; @@ -1029,7 +1029,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match token.kind { token::Interpolated(nt, _) => { let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span); - self.lower_token_stream(tts) + TokenTree::Delimited( + DelimSpan::from_single(token.span), + DelimToken::NoDelim, + self.lower_token_stream(tts), + ) + .into() } _ => TokenTree::Token(token).into(), } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 8cdb5b09c9e8b..7101525b30977 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -387,6 +387,7 @@ pub fn compile_declarative_macro( def: &ast::Item, edition: Edition, ) -> SyntaxExtension { + debug!("compile_declarative_macro: {:?}", def); let mk_syn_ext = |expander| { SyntaxExtension::new( sess, diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index e2f601371b1ee..d29f7380d9ee7 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1049,6 +1049,7 @@ impl<'tcx> TyCtxt<'tcx> { Some(attr) => attr, None => return Bound::Unbounded, }; + debug!("layout_scalar_valid_range: attr={:?}", attr); for meta in attr.meta_item_list().expect("rustc_layout_scalar_valid_range takes args") { match meta.literal().expect("attribute takes lit").kind { ast::LitKind::Int(a, _) => return Bound::Included(a), diff --git a/src/test/ui/macros/doc-comment.rs b/src/test/ui/macros/doc-comment.rs new file mode 100644 index 0000000000000..9de39e9b56c98 --- /dev/null +++ b/src/test/ui/macros/doc-comment.rs @@ -0,0 +1,25 @@ +// check-pass +// Tests that we properly handle a nested macro expansion +// involving a `#[doc]` attribute +#![deny(missing_docs)] +//! Crate docs + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + } +} + +macro_rules! make_comment { + () => { + doc_comment!("Function docs", + pub fn bar() {} + ); + } +} + + +make_comment!(); + +fn main() {} diff --git a/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs b/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs new file mode 100644 index 0000000000000..52ebe8e7fb2ef --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/nested-macro-rules.rs @@ -0,0 +1,15 @@ +pub struct FirstStruct; + +#[macro_export] +macro_rules! outer_macro { + ($name:ident) => { + #[macro_export] + macro_rules! inner_macro { + ($wrapper:ident) => { + $wrapper!($name) + } + } + } +} + +outer_macro!(FirstStruct); diff --git a/src/test/ui/proc-macro/auxiliary/test-macros.rs b/src/test/ui/proc-macro/auxiliary/test-macros.rs index fb8016cd43896..8682ebdd109f0 100644 --- a/src/test/ui/proc-macro/auxiliary/test-macros.rs +++ b/src/test/ui/proc-macro/auxiliary/test-macros.rs @@ -101,6 +101,12 @@ pub fn print_bang(input: TokenStream) -> TokenStream { print_helper(input, "BANG") } +#[proc_macro] +pub fn print_bang_consume(input: TokenStream) -> TokenStream { + print_helper(input, "BANG"); + TokenStream::new() +} + #[proc_macro_attribute] pub fn print_attr(_: TokenStream, input: TokenStream) -> TokenStream { print_helper(input, "ATTR") diff --git a/src/test/ui/proc-macro/nested-macro-rules.rs b/src/test/ui/proc-macro/nested-macro-rules.rs new file mode 100644 index 0000000000000..2f8ef20232782 --- /dev/null +++ b/src/test/ui/proc-macro/nested-macro-rules.rs @@ -0,0 +1,20 @@ +// run-pass +// aux-build:nested-macro-rules.rs +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// edition:2018 + +extern crate nested_macro_rules; +extern crate test_macros; + +use test_macros::print_bang; + +use nested_macro_rules::FirstStruct; +struct SecondStruct; + +fn main() { + nested_macro_rules::inner_macro!(print_bang); + + nested_macro_rules::outer_macro!(SecondStruct); + inner_macro!(print_bang); +} diff --git a/src/test/ui/proc-macro/nested-macro-rules.stdout b/src/test/ui/proc-macro/nested-macro-rules.stdout new file mode 100644 index 0000000000000..429c1f927fc47 --- /dev/null +++ b/src/test/ui/proc-macro/nested-macro-rules.stdout @@ -0,0 +1,27 @@ +PRINT-BANG INPUT (DISPLAY): FirstStruct +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "FirstStruct", + span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#3), + }, + ], + span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#3), + }, +] +PRINT-BANG INPUT (DISPLAY): SecondStruct +PRINT-BANG RE-COLLECTED (DISPLAY): SecondStruct +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "SecondStruct", + span: $DIR/nested-macro-rules.rs:18:38: 18:50 (#9), + }, + ], + span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#8), + }, +] diff --git a/src/test/ui/proc-macro/nodelim-groups.rs b/src/test/ui/proc-macro/nodelim-groups.rs new file mode 100644 index 0000000000000..cfcd4c0d2a658 --- /dev/null +++ b/src/test/ui/proc-macro/nodelim-groups.rs @@ -0,0 +1,19 @@ +// run-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// edition:2018 +// +// Tests the pretty-printing behavior of inserting `NoDelim` groups + +extern crate test_macros; +use test_macros::print_bang_consume; + +macro_rules! expand_it { + (($val1:expr) ($val2:expr)) => { expand_it!($val1 + $val2) }; + ($val:expr) => { print_bang_consume!("hi" $val (1 + 1)) }; +} + +fn main() { + expand_it!(1 + (25) + 1); + expand_it!(("hello".len()) ("world".len())); +} diff --git a/src/test/ui/proc-macro/nodelim-groups.stdout b/src/test/ui/proc-macro/nodelim-groups.stdout new file mode 100644 index 0000000000000..75a189a9fcdea --- /dev/null +++ b/src/test/ui/proc-macro/nodelim-groups.stdout @@ -0,0 +1,156 @@ +PRINT-BANG INPUT (DISPLAY): "hi" 1 + (25) + 1 (1 + 1) +PRINT-BANG INPUT (DEBUG): TokenStream [ + Literal { + kind: Str, + symbol: "hi", + suffix: None, + span: $DIR/nodelim-groups.rs:13:42: 13:46 (#3), + }, + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/nodelim-groups.rs:17:16: 17:17 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nodelim-groups.rs:17:18: 17:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "25", + suffix: None, + span: $DIR/nodelim-groups.rs:17:21: 17:23 (#0), + }, + ], + span: $DIR/nodelim-groups.rs:17:20: 17:24 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nodelim-groups.rs:17:25: 17:26 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/nodelim-groups.rs:17:27: 17:28 (#0), + }, + ], + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#3), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/nodelim-groups.rs:13:53: 13:54 (#3), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nodelim-groups.rs:13:55: 13:56 (#3), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/nodelim-groups.rs:13:57: 13:58 (#3), + }, + ], + span: $DIR/nodelim-groups.rs:13:52: 13:59 (#3), + }, +] +PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1) +PRINT-BANG RE-COLLECTED (DISPLAY): "hi" "hello" . len() + "world" . len() (1 + 1) +PRINT-BANG INPUT (DEBUG): TokenStream [ + Literal { + kind: Str, + symbol: "hi", + suffix: None, + span: $DIR/nodelim-groups.rs:13:42: 13:46 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "hello", + suffix: None, + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Punct { + ch: '.', + spacing: Alone, + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Ident { + ident: "len", + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Literal { + kind: Str, + symbol: "world", + suffix: None, + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Punct { + ch: '.', + spacing: Alone, + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Ident { + ident: "len", + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + ], + span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/nodelim-groups.rs:13:53: 13:54 (#8), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nodelim-groups.rs:13:55: 13:56 (#8), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/nodelim-groups.rs:13:57: 13:58 (#8), + }, + ], + span: $DIR/nodelim-groups.rs:13:52: 13:59 (#8), + }, +] diff --git a/src/test/ui/unsafe/ranged_ints_macro.rs b/src/test/ui/unsafe/ranged_ints_macro.rs new file mode 100644 index 0000000000000..9192ecfe196cb --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints_macro.rs @@ -0,0 +1,16 @@ +// build-pass +#![feature(rustc_attrs)] + +macro_rules! apply { + ($val:expr) => { + #[rustc_layout_scalar_valid_range_start($val)] + #[repr(transparent)] + pub(crate) struct NonZero(pub(crate) T); + } +} + +apply!(1); + +fn main() { + let _x = unsafe { NonZero(1) }; +} From c84402872ec9ced6f5ba16b48c4f45fef96ad591 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 21 Jun 2020 16:56:10 -0400 Subject: [PATCH 87/92] Don't print additional spaces when pretty-printing NoDelim groups --- src/librustc_ast_pretty/pprust.rs | 2 +- src/test/ui/proc-macro/input-interpolated.stdout | 1 - src/test/ui/proc-macro/nested-macro-rules.stdout | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 86faa1f086ce2..37e18312282a4 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -245,7 +245,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) token::CloseDelim(token::Bracket) => "]".to_string(), token::OpenDelim(token::Brace) => "{".to_string(), token::CloseDelim(token::Brace) => "}".to_string(), - token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => " ".to_string(), + token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(), token::Pound => "#".to_string(), token::Dollar => "$".to_string(), token::Question => "?".to_string(), diff --git a/src/test/ui/proc-macro/input-interpolated.stdout b/src/test/ui/proc-macro/input-interpolated.stdout index 7529db3bd06f8..791e907245242 100644 --- a/src/test/ui/proc-macro/input-interpolated.stdout +++ b/src/test/ui/proc-macro/input-interpolated.stdout @@ -1,5 +1,4 @@ PRINT-BANG INPUT (DISPLAY): A -PRINT-BANG RE-COLLECTED (DISPLAY): A PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, diff --git a/src/test/ui/proc-macro/nested-macro-rules.stdout b/src/test/ui/proc-macro/nested-macro-rules.stdout index 429c1f927fc47..e4cfe020324b8 100644 --- a/src/test/ui/proc-macro/nested-macro-rules.stdout +++ b/src/test/ui/proc-macro/nested-macro-rules.stdout @@ -1,4 +1,4 @@ -PRINT-BANG INPUT (DISPLAY): FirstStruct +PRINT-BANG INPUT (DISPLAY): FirstStruct PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, @@ -12,7 +12,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ }, ] PRINT-BANG INPUT (DISPLAY): SecondStruct -PRINT-BANG RE-COLLECTED (DISPLAY): SecondStruct PRINT-BANG INPUT (DEBUG): TokenStream [ Group { delimiter: None, From 1ded7a581589b65be35724ea00bb5cec4e13c673 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 29 Jun 2020 09:55:28 -0400 Subject: [PATCH 88/92] Handle `None`-delimited groups when parsing `macro_rules!` macro When a `macro_rules!` macro expands to another `macro_rules!` macro, we may see `None`-delimited groups in odd places when another crate deserializes the 'inner' macro. This commit 'unwraps' an outer `None`-delimited group to avoid breaking existing code. See https://github.com/rust-lang/rust/pull/73569#issuecomment-650860457 for more details. The proper fix is to handle `None`-delimited groups systematically throughout the parser, but that will require significant work. In the meantime, this hack lets us fix important hygiene bugs in macros --- src/librustc_expand/mbe/quoted.rs | 110 ++++++++++-------- .../ui/proc-macro/auxiliary/meta-delim.rs | 12 ++ src/test/ui/proc-macro/meta-delim.rs | 12 ++ 3 files changed, 87 insertions(+), 47 deletions(-) create mode 100644 src/test/ui/proc-macro/auxiliary/meta-delim.rs create mode 100644 src/test/ui/proc-macro/meta-delim.rs diff --git a/src/librustc_expand/mbe/quoted.rs b/src/librustc_expand/mbe/quoted.rs index de66c2ada40e6..09306f26ee0ad 100644 --- a/src/librustc_expand/mbe/quoted.rs +++ b/src/librustc_expand/mbe/quoted.rs @@ -90,7 +90,7 @@ pub(super) fn parse( /// # Parameters /// /// - `tree`: the tree we wish to convert. -/// - `trees`: an iterator over trees. We may need to read more tokens from it in order to finish +/// - `outer_trees`: an iterator over trees. We may need to read more tokens from it in order to finish /// converting `tree` /// - `expect_matchers`: same as for `parse` (see above). /// - `sess`: the parsing session. Any errors will be emitted to this session. @@ -98,7 +98,7 @@ pub(super) fn parse( /// unstable features or not. fn parse_tree( tree: tokenstream::TokenTree, - trees: &mut impl Iterator, + outer_trees: &mut impl Iterator, expect_matchers: bool, sess: &ParseSess, node_id: NodeId, @@ -106,56 +106,72 @@ fn parse_tree( // Depending on what `tree` is, we could be parsing different parts of a macro match tree { // `tree` is a `$` token. Look at the next token in `trees` - tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }) => match trees.next() { - // `tree` is followed by a delimited set of token trees. This indicates the beginning - // of a repetition sequence in the macro (e.g. `$(pat)*`). - Some(tokenstream::TokenTree::Delimited(span, delim, tts)) => { - // Must have `(` not `{` or `[` - if delim != token::Paren { - let tok = pprust::token_kind_to_string(&token::OpenDelim(delim)); - let msg = format!("expected `(`, found `{}`", tok); - sess.span_diagnostic.span_err(span.entire(), &msg); - } - // Parse the contents of the sequence itself - let sequence = parse(tts, expect_matchers, sess, node_id); - // Get the Kleene operator and optional separator - let (separator, kleene) = parse_sep_and_kleene_op(trees, span.entire(), sess); - // Count the number of captured "names" (i.e., named metavars) - let name_captures = macro_parser::count_names(&sequence); - TokenTree::Sequence( - span, - Lrc::new(SequenceRepetition { - tts: sequence, - separator, - kleene, - num_captures: name_captures, - }), - ) + tokenstream::TokenTree::Token(Token { kind: token::Dollar, span }) => { + // FIXME: Handle `None`-delimited groups in a more systematic way + // during parsing. + let mut next = outer_trees.next(); + let mut trees: Box>; + if let Some(tokenstream::TokenTree::Delimited(_, token::NoDelim, tts)) = next { + trees = Box::new(tts.into_trees()); + next = trees.next(); + } else { + trees = Box::new(outer_trees); } - // `tree` is followed by an `ident`. This could be `$meta_var` or the `$crate` special - // metavariable that names the crate of the invocation. - Some(tokenstream::TokenTree::Token(token)) if token.is_ident() => { - let (ident, is_raw) = token.ident().unwrap(); - let span = ident.span.with_lo(span.lo()); - if ident.name == kw::Crate && !is_raw { - TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span) - } else { - TokenTree::MetaVar(span, ident) + match next { + // `tree` is followed by a delimited set of token trees. This indicates the beginning + // of a repetition sequence in the macro (e.g. `$(pat)*`). + Some(tokenstream::TokenTree::Delimited(span, delim, tts)) => { + // Must have `(` not `{` or `[` + if delim != token::Paren { + let tok = pprust::token_kind_to_string(&token::OpenDelim(delim)); + let msg = format!("expected `(`, found `{}`", tok); + sess.span_diagnostic.span_err(span.entire(), &msg); + } + // Parse the contents of the sequence itself + let sequence = parse(tts, expect_matchers, sess, node_id); + // Get the Kleene operator and optional separator + let (separator, kleene) = + parse_sep_and_kleene_op(&mut trees, span.entire(), sess); + // Count the number of captured "names" (i.e., named metavars) + let name_captures = macro_parser::count_names(&sequence); + TokenTree::Sequence( + span, + Lrc::new(SequenceRepetition { + tts: sequence, + separator, + kleene, + num_captures: name_captures, + }), + ) } - } - // `tree` is followed by a random token. This is an error. - Some(tokenstream::TokenTree::Token(token)) => { - let msg = - format!("expected identifier, found `{}`", pprust::token_to_string(&token),); - sess.span_diagnostic.span_err(token.span, &msg); - TokenTree::MetaVar(token.span, Ident::invalid()) - } + // `tree` is followed by an `ident`. This could be `$meta_var` or the `$crate` special + // metavariable that names the crate of the invocation. + Some(tokenstream::TokenTree::Token(token)) if token.is_ident() => { + let (ident, is_raw) = token.ident().unwrap(); + let span = ident.span.with_lo(span.lo()); + if ident.name == kw::Crate && !is_raw { + TokenTree::token(token::Ident(kw::DollarCrate, is_raw), span) + } else { + TokenTree::MetaVar(span, ident) + } + } - // There are no more tokens. Just return the `$` we already have. - None => TokenTree::token(token::Dollar, span), - }, + // `tree` is followed by a random token. This is an error. + Some(tokenstream::TokenTree::Token(token)) => { + let msg = format!( + "expected identifier, found `{}`", + pprust::token_to_string(&token), + ); + sess.span_diagnostic.span_err(token.span, &msg); + TokenTree::MetaVar(token.span, Ident::invalid()) + } + + // There are no more tokens. Just return the `$` we already have. + None => TokenTree::token(token::Dollar, span), + } + } // `tree` is an arbitrary token. Keep it. tokenstream::TokenTree::Token(token) => TokenTree::Token(token), diff --git a/src/test/ui/proc-macro/auxiliary/meta-delim.rs b/src/test/ui/proc-macro/auxiliary/meta-delim.rs new file mode 100644 index 0000000000000..54e3d7857267b --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/meta-delim.rs @@ -0,0 +1,12 @@ +macro_rules! produce_it { + ($dollar_one:tt $foo:ident $my_name:ident) => { + #[macro_export] + macro_rules! meta_delim { + ($dollar_one ($dollar_one $my_name:ident)*) => { + stringify!($dollar_one ($dollar_one $my_name)*) + } + } + } +} + +produce_it!($my_name name); diff --git a/src/test/ui/proc-macro/meta-delim.rs b/src/test/ui/proc-macro/meta-delim.rs new file mode 100644 index 0000000000000..964291bc6784c --- /dev/null +++ b/src/test/ui/proc-macro/meta-delim.rs @@ -0,0 +1,12 @@ +// aux-build:meta-delim.rs +// edition:2018 +// run-pass + +// Tests that we can properly deserialize a macro with strange delimiters +// See https://github.com/rust-lang/rust/pull/73569#issuecomment-650860457 + +extern crate meta_delim; + +fn main() { + assert_eq!("a bunch of idents", meta_delim::meta_delim!(a bunch of idents)); +} From 67b162f043e7e52e71b7ae8bbbdb0a732ec85eb1 Mon Sep 17 00:00:00 2001 From: aspen Date: Wed, 1 Jul 2020 13:19:09 -0400 Subject: [PATCH 89/92] Explicitly check for iOS/tvOS. --- src/bootstrap/native.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 70c292e229da8..cceb794165059 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -176,7 +176,7 @@ impl Step for Llvm { } // Are we compiling for iOS/tvOS? - if target.contains("apple") && !target.contains("darwin") { + if target.contains("apple-ios") || target.contains("apple-tvos") { // These two defines prevent CMake from automatically trying to add a MacOSX sysroot, which leads to a compiler error. cfg.define("CMAKE_OSX_SYSROOT", "/"); cfg.define("CMAKE_OSX_DEPLOYMENT_TARGET", ""); From eb4ba55055393961a51ae47fee1e734e095d91ef Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 1 Jul 2020 20:23:06 +0300 Subject: [PATCH 90/92] Add an issue number for the pretty_printing_compatibility_hack FIXME --- src/librustc_ast/token.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index 0f0428574de0f..173ea5e48d682 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -782,7 +782,7 @@ impl Nonterminal { /// We need to maintain some special pretty-printing behavior for them due to incorrect /// asserts in old versions of those crates and their wide use in the ecosystem. /// See issue #73345 for more details. - /// FIXME: Remove this eventually. + /// FIXME(#73933): Remove this eventually. pub fn pretty_printing_compatibility_hack(&self) -> bool { if let NtItem(item) = self { let name = item.ident.name; From 86d8644c1bfa4b8feddfa588e8e599e420acd040 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 26 Jun 2020 13:20:41 +0100 Subject: [PATCH 91/92] Optimise fast path of checked_ops with `unlikely` --- src/libcore/num/mod.rs | 70 ++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index d36da90f2adc9..60c496ba2d3c4 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -21,6 +21,21 @@ macro_rules! try_opt { }; } +#[cfg(bootstrap)] +macro_rules! unlikely { + ($e: expr) => { + $e + }; +} + +#[cfg(not(bootstrap))] +#[allow_internal_unstable(const_likely)] +macro_rules! unlikely { + ($e: expr) => { + intrinsics::unlikely($e) + }; +} + macro_rules! impl_nonzero_fmt { ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( @@ -745,7 +760,7 @@ $EndFeature, " #[inline] pub const fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -787,7 +802,7 @@ $EndFeature, " #[inline] pub const fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -829,7 +844,7 @@ $EndFeature, " #[inline] pub const fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -871,7 +886,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option { - if rhs == 0 || (self == Self::MIN && rhs == -1) { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -900,7 +915,7 @@ assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); without modifying the original"] #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if rhs == 0 || (self == Self::MIN && rhs == -1) { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { None } else { Some(self.div_euclid(rhs)) @@ -929,7 +944,7 @@ $EndFeature, " without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option { - if rhs == 0 || (self == Self::MIN && rhs == -1) { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { None } else { // SAFETY: div by zero and by INT_MIN have been checked above @@ -957,7 +972,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); without modifying the original"] #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if rhs == 0 || (self == Self::MIN && rhs == -1) { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { None } else { Some(self.rem_euclid(rhs)) @@ -983,7 +998,7 @@ $EndFeature, " #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -1007,7 +1022,7 @@ $EndFeature, " #[inline] pub const fn checked_shl(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shl(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -1031,7 +1046,7 @@ $EndFeature, " #[inline] pub const fn checked_shr(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shr(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -1738,7 +1753,7 @@ $EndFeature, " #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - if self == Self::MIN && rhs == -1 { + if unlikely!(self == Self::MIN && rhs == -1) { (self, true) } else { (self / rhs, false) @@ -1771,7 +1786,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringi #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - if self == Self::MIN && rhs == -1 { + if unlikely!(self == Self::MIN && rhs == -1) { (self, true) } else { (self.div_euclid(rhs), false) @@ -1805,7 +1820,7 @@ $EndFeature, " #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - if self == Self::MIN && rhs == -1 { + if unlikely!(self == Self::MIN && rhs == -1) { (0, true) } else { (self % rhs, false) @@ -1838,7 +1853,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); without modifying the original"] #[inline] pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - if self == Self::MIN && rhs == -1 { + if unlikely!(self == Self::MIN && rhs == -1) { (0, true) } else { (self.rem_euclid(rhs), false) @@ -1869,7 +1884,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($Self #[allow(unused_attributes)] #[cfg_attr(bootstrap, allow_internal_unstable(const_if_match))] pub const fn overflowing_neg(self) -> (Self, bool) { - if self == Self::MIN { + if unlikely!(self == Self::MIN) { (Self::MIN, true) } else { (-self, false) @@ -2981,7 +2996,7 @@ assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeat #[inline] pub const fn checked_add(self, rhs: Self) -> Option { let (a, b) = self.overflowing_add(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -3021,7 +3036,7 @@ assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " #[inline] pub const fn checked_sub(self, rhs: Self) -> Option { let (a, b) = self.overflowing_sub(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -3061,7 +3076,7 @@ assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, " #[inline] pub const fn checked_mul(self, rhs: Self) -> Option { let (a, b) = self.overflowing_mul(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -3100,11 +3115,12 @@ assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " without modifying the original"] #[inline] pub const fn checked_div(self, rhs: Self) -> Option { - match rhs { - 0 => None, + if unlikely!(rhs == 0) { + None + } else { // SAFETY: div by zero has been checked above and unsigned types have no other // failure modes for division - rhs => Some(unsafe { intrinsics::unchecked_div(self, rhs) }), + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) } } } @@ -3127,7 +3143,7 @@ assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); without modifying the original"] #[inline] pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if rhs == 0 { + if unlikely!(rhs == 0) { None } else { Some(self.div_euclid(rhs)) @@ -3154,7 +3170,7 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " without modifying the original"] #[inline] pub const fn checked_rem(self, rhs: Self) -> Option { - if rhs == 0 { + if unlikely!(rhs == 0) { None } else { // SAFETY: div by zero has been checked above and unsigned types have no other @@ -3182,7 +3198,7 @@ assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); without modifying the original"] #[inline] pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if rhs == 0 { + if unlikely!(rhs == 0) { None } else { Some(self.rem_euclid(rhs)) @@ -3209,7 +3225,7 @@ assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " #[inline] pub const fn checked_neg(self) -> Option { let (a, b) = self.overflowing_neg(); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -3232,7 +3248,7 @@ assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, #[inline] pub const fn checked_shl(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shl(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } @@ -3255,7 +3271,7 @@ assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, #[inline] pub const fn checked_shr(self, rhs: u32) -> Option { let (a, b) = self.overflowing_shr(rhs); - if b {None} else {Some(a)} + if unlikely!(b) {None} else {Some(a)} } } From 0b9bc79738d3a0bc9672b29196d478e9e7f177cd Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 1 Jul 2020 15:51:35 -0700 Subject: [PATCH 92/92] Tests for number of times rustdoc is built with x.py test and doc. --- src/bootstrap/builder/tests.rs | 79 ++++++++++++++++++++++++++++++++++ src/bootstrap/doc.rs | 25 +++++------ src/bootstrap/tool.rs | 4 +- 3 files changed, 94 insertions(+), 14 deletions(-) diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index cca8ab80c93b1..1e75e67af0c9e 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -54,6 +54,11 @@ fn dist_baseline() { &[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },] ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); + // Make sure rustdoc is only built once. + assert_eq!( + first(builder.cache.all::()), + &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },] + ); } #[test] @@ -414,3 +419,77 @@ fn test_exclude() { // Ensure other tests are not affected. assert!(builder.cache.contains::()); } + +#[test] +fn doc_default() { + let mut config = configure(&[], &[]); + config.compiler_docs = true; + config.cmd = Subcommand::Doc { paths: Vec::new(), open: false }; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]); + let a = INTERNER.intern_str("A"); + + // error_index_generator uses stage 1 to share rustdoc artifacts with the + // rustdoc tool. + assert_eq!( + first(builder.cache.all::()), + &[doc::ErrorIndex { compiler: Compiler { host: a, stage: 1 }, target: a },] + ); + assert_eq!( + first(builder.cache.all::()), + &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }] + ); + // This is actually stage 1, but Rustdoc::run swaps out the compiler with + // stage minus 1 if --stage is not 0. Very confusing! + assert_eq!( + first(builder.cache.all::()), + &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },] + ); +} + +#[test] +fn test_docs() { + // Behavior of `x.py test` doing various documentation tests. + let mut config = configure(&[], &[]); + config.cmd = Subcommand::Test { + paths: vec![], + test_args: vec![], + rustc_args: vec![], + fail_fast: true, + doc_tests: DocTests::Yes, + bless: false, + compare_mode: None, + rustfix_coverage: false, + pass: None, + }; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]); + let a = INTERNER.intern_str("A"); + + // error_index_generator uses stage 1 to share rustdoc artifacts with the + // rustdoc tool. + assert_eq!( + first(builder.cache.all::()), + &[doc::ErrorIndex { compiler: Compiler { host: a, stage: 1 }, target: a },] + ); + assert_eq!( + first(builder.cache.all::()), + &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }] + ); + // Unfortunately rustdoc is built twice. Once from stage1 for compiletest + // (and other things), and once from stage0 for std crates. Ideally it + // would only be built once. If someone wants to fix this, it might be + // worth investigating if it would be possible to test std from stage1. + // Note that the stages here are +1 than what they actually are because + // Rustdoc::run swaps out the compiler with stage minus 1 if --stage is + // not 0. + assert_eq!( + first(builder.cache.all::()), + &[ + tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, + tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } }, + ] + ); +} diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 6d781c8e45607..d02c19467ee68 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -637,9 +637,10 @@ impl Step for Rustdoc { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { - target: Interned, + pub compiler: Compiler, + pub target: Interned, } impl Step for ErrorIndex { @@ -653,22 +654,22 @@ impl Step for ErrorIndex { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(ErrorIndex { target: run.target }); + let target = run.target; + // error_index_generator depends on librustdoc. Use the compiler that + // is normally used to build rustdoc for other documentation so that + // it shares the same artifacts. + let compiler = + run.builder.compiler_for(run.builder.top_stage, run.builder.config.build, target); + run.builder.ensure(ErrorIndex { compiler, target }); } /// Generates the HTML rendered error-index by running the /// `error_index_generator` tool. fn run(self, builder: &Builder<'_>) { - let target = self.target; - - builder.info(&format!("Documenting error index ({})", target)); - let out = builder.doc_out(target); + builder.info(&format!("Documenting error index ({})", self.target)); + let out = builder.doc_out(self.target); t!(fs::create_dir_all(&out)); - // error_index_generator depends on librustdoc. Use the compiler that - // is normally used to build rustdoc for other documentation so that - // it shares the same artifacts. - let compiler = builder.compiler_for(builder.top_stage, builder.config.build, target); - let mut index = tool::ErrorIndex::command(builder, compiler); + let mut index = tool::ErrorIndex::command(builder, self.compiler); index.arg("html"); index.arg(out.join("error-index.html")); index.arg(crate::channel::CFG_RELEASE_NUM); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index b3fa3b49855fd..45f5073f43100 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -366,7 +366,7 @@ bootstrap_tool!( ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; ); -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct ErrorIndex { pub compiler: Compiler, } @@ -449,7 +449,7 @@ impl Step for RemoteTestServer { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] pub struct Rustdoc { /// This should only ever be 0 or 2. /// We sometimes want to reference the "bootstrap" rustdoc, which is why this option is here.