From a1c884682c9c056990327aa86b2d966771b1e492 Mon Sep 17 00:00:00 2001
From: Pietro Albini <pietro@pietroalbini.org>
Date: Mon, 7 Jun 2021 17:08:13 +0200
Subject: [PATCH 1/3] ignore ui-fulldeps/session-derive-errors.rs on beta and
 stable

The session-derive-errors test ensures the internal SessionDiagnostic
derive macro outputs the right error messages when misused.

The macro relies on the proc_macro2 crate though, which changes its span
behavior depending on whether the channel is nightly or not. This caused
test failures when bumping the channel from nightly to beta/stable.

Since SessionDiagnostic is internal-only we don't care about its
diagnostics quality outside of nightly, as the compiler itself is
developed on nightly. Thus the easiest solution is to ignore that test
on the beta and stable channels.

This also implements `// only-{channel}` and `// ignore-{channel}` in
compiletest to properly support the change.
---
 src/bootstrap/test.rs                         |  2 ++
 src/test/ui-fulldeps/session-derive-errors.rs |  6 ++++
 .../ui-fulldeps/session-derive-errors.stderr  | 36 +++++++++----------
 src/tools/compiletest/src/common.rs           |  3 ++
 src/tools/compiletest/src/header.rs           |  1 +
 src/tools/compiletest/src/header/tests.rs     | 15 ++++++++
 src/tools/compiletest/src/main.rs             |  4 ++-
 7 files changed, 48 insertions(+), 19 deletions(-)

diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index cc7c143d474..38d2fe8f5ac 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1517,6 +1517,8 @@ note: if you're sure you want to do this, please open an issue as to why. In the
 
         cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo);
 
+        cmd.arg("--channel").arg(&builder.config.channel);
+
         builder.ci_env.force_coloring_in_ci(&mut cmd);
 
         builder.info(&format!(
diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs
index 7967b32a4a4..140aaad3b38 100644
--- a/src/test/ui-fulldeps/session-derive-errors.rs
+++ b/src/test/ui-fulldeps/session-derive-errors.rs
@@ -1,6 +1,12 @@
 // check-fail
 // Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
 
+// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
+// changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
+// the test is just ignored on stable and beta:
+// ignore-beta
+// ignore-stable
+
 #![feature(rustc_private)]
 #![crate_type = "lib"]
 
diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr
index c6c3765b80d..2f1debe25b7 100644
--- a/src/test/ui-fulldeps/session-derive-errors.stderr
+++ b/src/test/ui-fulldeps/session-derive-errors.stderr
@@ -1,5 +1,5 @@
 error: `#[derive(SessionDiagnostic)]` can only be used on structs
-  --> $DIR/session-derive-errors.rs:28:1
+  --> $DIR/session-derive-errors.rs:34:1
    |
 LL | / #[error = "E0123"]
 LL | |
@@ -10,31 +10,31 @@ LL | | }
    | |_^
 
 error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute
-  --> $DIR/session-derive-errors.rs:37:1
+  --> $DIR/session-derive-errors.rs:43:1
    |
 LL | #[label = "This is in the wrong place"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute
-  --> $DIR/session-derive-errors.rs:44:5
+  --> $DIR/session-derive-errors.rs:50:5
    |
 LL |     #[suggestion = "this is the wrong kind of attribute"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `error` specified multiple times
-  --> $DIR/session-derive-errors.rs:52:11
+  --> $DIR/session-derive-errors.rs:58:11
    |
 LL | #[error = "E0456"]
    |           ^^^^^^^
 
 error: `lint` specified when `error` was already specified
-  --> $DIR/session-derive-errors.rs:58:10
+  --> $DIR/session-derive-errors.rs:64:10
    |
 LL | #[lint = "some_useful_lint"]
    |          ^^^^^^^^^^^^^^^^^^
 
 error: `code` not specified
-  --> $DIR/session-derive-errors.rs:67:1
+  --> $DIR/session-derive-errors.rs:73:1
    |
 LL | struct ErrorCodeNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,19 +42,19 @@ LL | struct ErrorCodeNotProvided {}
    = help: use the [code = "..."] attribute to set this diagnostic's error code 
 
 error: the `#[message = "..."]` attribute can only be applied to fields of type Span
-  --> $DIR/session-derive-errors.rs:95:5
+  --> $DIR/session-derive-errors.rs:101:5
    |
 LL |     #[message = "this message is applied to a String field"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/session-derive-errors.rs:102:1
+  --> $DIR/session-derive-errors.rs:108:1
    |
 LL | #[message = "This error has a field, and references {name}"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/session-derive-errors.rs:110:1
+  --> $DIR/session-derive-errors.rs:116:1
    |
 LL | #[error = "E0123"]
    |               - because of this opening brace
@@ -65,7 +65,7 @@ LL | #[message = "This is missing a closing brace: {name"]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
-  --> $DIR/session-derive-errors.rs:119:1
+  --> $DIR/session-derive-errors.rs:125:1
    |
 LL | #[message = "This is missing an opening brace: name}"]
    | ^ unmatched `}` in format string
@@ -74,25 +74,25 @@ LL | #[message = "This is missing an opening brace: name}"]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: The `#[label = ...]` attribute can only be applied to fields of type Span
-  --> $DIR/session-derive-errors.rs:138:5
+  --> $DIR/session-derive-errors.rs:144:5
    |
 LL |     #[label = "See here"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: `nonsense` is not a valid key for `#[suggestion(...)]`
-  --> $DIR/session-derive-errors.rs:163:18
+  --> $DIR/session-derive-errors.rs:169:18
    |
 LL |     #[suggestion(nonsense = "This is nonsense")]
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `msg` is not a valid key for `#[suggestion(...)]`
-  --> $DIR/session-derive-errors.rs:171:18
+  --> $DIR/session-derive-errors.rs:177:18
    |
 LL |     #[suggestion(msg = "This is a suggestion")]
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing suggestion message
-  --> $DIR/session-derive-errors.rs:179:7
+  --> $DIR/session-derive-errors.rs:185:7
    |
 LL |     #[suggestion(code = "This is suggested code")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     #[suggestion(code = "This is suggested code")]
    = help: provide a suggestion message using #[suggestion(message = "...")]
 
 error: wrong field type for suggestion
-  --> $DIR/session-derive-errors.rs:194:5
+  --> $DIR/session-derive-errors.rs:200:5
    |
 LL | /     #[suggestion(message = "This is a message", code = "This is suggested code")]
 LL | |
@@ -110,7 +110,7 @@ LL | |     suggestion: Applicability,
    = help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Span
-  --> $DIR/session-derive-errors.rs:209:5
+  --> $DIR/session-derive-errors.rs:215:5
    |
 LL | /     #[suggestion(message = "This is a message", code = "This is suggested code")]
 LL | |
@@ -118,7 +118,7 @@ LL | |     suggestion: (Span, Span, Applicability),
    | |___________________________________________^
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/session-derive-errors.rs:217:5
+  --> $DIR/session-derive-errors.rs:223:5
    |
 LL | /     #[suggestion(message = "This is a message", code = "This is suggested code")]
 LL | |
@@ -126,7 +126,7 @@ LL | |     suggestion: (Applicability, Applicability, Span),
    | |____________________________________________________^
 
 error: invalid annotation list `#[label(...)]`
-  --> $DIR/session-derive-errors.rs:225:7
+  --> $DIR/session-derive-errors.rs:231:7
    |
 LL |     #[label("wrong kind of annotation for label")]
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 408c0b8da0b..a5b526be86f 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -346,6 +346,9 @@ pub struct Config {
     /// whether to run `tidy` when a rustdoc test fails
     pub has_tidy: bool,
 
+    /// The current Rust channel
+    pub channel: String,
+
     // Configuration for various run-make tests frobbing things like C compilers
     // or querying about various LLVM component information.
     pub cc: String,
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 983934d129a..703c5804e22 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -876,6 +876,7 @@ impl Config {
             name == util::get_arch(&self.target) ||             // architecture
             name == util::get_pointer_width(&self.target) ||    // pointer width
             name == self.stage_id.split('-').next().unwrap() || // stage
+            name == self.channel ||                             // channel
             (self.target != self.host && name == "cross-compile") ||
             (name == "endian-big" && util::is_big_endian(&self.target)) ||
             (self.remote_test_client.is_some() && name == "remote") ||
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index ca7458d255c..2c607b6a50e 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -55,6 +55,7 @@ fn config() -> Config {
         "--llvm-components=",
         "--android-cross-path=",
         "--target=x86_64-unknown-linux-gnu",
+        "--channel=nightly",
     ];
     let args = args.iter().map(ToString::to_string).collect();
     crate::parse_config(args)
@@ -234,6 +235,20 @@ fn asm_support() {
     assert!(!parse_rs(&config, "// needs-asm-support").ignore);
 }
 
+#[test]
+fn channel() {
+    let mut config = config();
+    config.channel = "beta".into();
+
+    assert!(parse_rs(&config, "// ignore-beta").ignore);
+    assert!(parse_rs(&config, "// only-nightly").ignore);
+    assert!(parse_rs(&config, "// only-stable").ignore);
+
+    assert!(!parse_rs(&config, "// only-beta").ignore);
+    assert!(!parse_rs(&config, "// ignore-nightly").ignore);
+    assert!(!parse_rs(&config, "// ignore-stable").ignore);
+}
+
 #[test]
 fn test_extract_version_range() {
     use super::{extract_llvm_version, extract_version_range};
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 08ee8fc984d..c854663706a 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -144,7 +144,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "enable this to generate a Rustfix coverage file, which is saved in \
                 `./<build_base>/rustfix_missing_coverage.txt`",
         )
-        .optflag("h", "help", "show this message");
+        .optflag("h", "help", "show this message")
+        .reqopt("", "channel", "current Rust channel", "CHANNEL");
 
     let (argv0, args_) = args.split_first().unwrap();
     if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
@@ -278,6 +279,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         compare_mode: matches.opt_str("compare-mode").map(CompareMode::parse),
         rustfix_coverage: matches.opt_present("rustfix-coverage"),
         has_tidy,
+        channel: matches.opt_str("channel").unwrap(),
 
         cc: matches.opt_str("cc").unwrap(),
         cxx: matches.opt_str("cxx").unwrap(),

From b52bf1b41c8480326f3178d22c7d7524baf55361 Mon Sep 17 00:00:00 2001
From: Pietro Albini <pietro@pietroalbini.org>
Date: Mon, 7 Jun 2021 18:55:20 +0200
Subject: [PATCH 2/3] use channel-relative urls in rustdoc/intra-doc/field.rs

---
 src/test/rustdoc/intra-doc/field.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/test/rustdoc/intra-doc/field.rs b/src/test/rustdoc/intra-doc/field.rs
index c67c40a77ed..00114348924 100644
--- a/src/test/rustdoc/intra-doc/field.rs
+++ b/src/test/rustdoc/intra-doc/field.rs
@@ -1,4 +1,4 @@
-// @has field/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/ops/range/struct.Range.html#structfield.start"]' 'start'
-// @has field/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+// @has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start'
+// @has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
 //! [start][std::ops::Range::start]
 //! [not_found][std::io::ErrorKind::NotFound]

From 12d37e615faa179b90cbaf34e082fa0c03e416f8 Mon Sep 17 00:00:00 2001
From: Pietro Albini <pietro@pietroalbini.org>
Date: Mon, 7 Jun 2021 15:01:50 +0200
Subject: [PATCH 3/3] add the x86_64-gnu-stable job to test with stable channel

During the 1.52 release process we had to deal with some commits that
passed the test suite on the nightly branch but failed on the beta or
stable branch. In that case it was due to some UI tests including the
channel name in the output, but other changes might also be dependent on
the channel.

This commit adds a new CI job that runs the Linux x86_64 test suite with
the stable branch, ensuring nightly changes also work as stable.
---
 .github/workflows/ci.yml     |  5 +++++
 src/ci/docker/run.sh         |  1 +
 src/ci/github-actions/ci.yml | 11 +++++++++++
 src/ci/run.sh                |  6 +++++-
 4 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index aa9d97ba477..36362635b15 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -259,6 +259,11 @@ jobs:
           - name: x86_64-gnu
             os: ubuntu-latest-xl
             env: {}
+          - name: x86_64-gnu-stable
+            env:
+              IMAGE: x86_64-gnu
+              RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
+            os: ubuntu-latest-xl
           - name: x86_64-gnu-aux
             os: ubuntu-latest-xl
             env: {}
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index c2ff62e7481..3a47076722c 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -235,6 +235,7 @@ docker \
   --env TOOLSTATE_REPO_ACCESS_TOKEN \
   --env TOOLSTATE_REPO \
   --env TOOLSTATE_PUBLISH \
+  --env RUST_CI_OVERRIDE_RELEASE_CHANNEL \
   --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \
   --init \
   --rm \
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 343091cb779..e704071e401 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -407,6 +407,17 @@ jobs:
           - name: x86_64-gnu
             <<: *job-linux-xl
 
+          # This job ensures commits landing on nightly still pass the full
+          # test suite on the stable channel. There are some UI tests that
+          # depend on the channel being built (for example if they include the
+          # channel name on the output), and this builder prevents landing
+          # changes that would result in broken builds after a promotion.
+          - name: x86_64-gnu-stable
+            env:
+              IMAGE: x86_64-gnu
+              RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
+            <<: *job-linux-xl
+
           - name: x86_64-gnu-aux
             <<: *job-linux-xl
 
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 35f80a935c6..c5e225c7cd1 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -65,7 +65,11 @@ fi
 # Always set the release channel for bootstrap; this is normally not important (i.e., only dist
 # builds would seem to matter) but in practice bootstrap wants to know whether we're targeting
 # master, beta, or stable with a build to determine whether to run some checks (notably toolstate).
-export RUST_RELEASE_CHANNEL="$(cat "${ci_dir}/channel")"
+if [[ -z "${RUST_CI_OVERRIDE_RELEASE_CHANNEL+x}" ]]; then
+    export RUST_RELEASE_CHANNEL="$(cat "${ci_dir}/channel")"
+else
+    export RUST_RELEASE_CHANNEL="${RUST_CI_OVERRIDE_RELEASE_CHANNEL}"
+fi
 RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
 
 if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then