about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-10-22 15:28:35 +0200
committerGitHub <noreply@github.com>2024-10-22 15:28:35 +0200
commit4d378f26a9e9cfa2efa279e0c59c111c47068784 (patch)
treedc0443f74c7f41ddd8238923110f4115cee9ed0c
parent916e9ced404f276e90171d7852d436b6ca92df56 (diff)
parentedc97a0df2fbff05dd03483938425d1590440c82 (diff)
downloadrust-4d378f26a9e9cfa2efa279e0c59c111c47068784.tar.gz
rust-4d378f26a9e9cfa2efa279e0c59c111c47068784.zip
Rollup merge of #125205 - ChrisDenton:verbatim-include, r=jieyouxu
Fixup Windows verbatim paths when used with the `include!` macro

On Windows, the following code can fail if the `OUT_DIR` environment variable is a [verbatim path](https://doc.rust-lang.org/std/path/enum.Prefix.html) (i.e. begins with `\\?\`):

```rust
include!(concat!(env!("OUT_DIR"), "/src/repro.rs"));
```

This is because verbatim paths treat `/` literally, as if it were just another character in the file name.

The good news is that the standard library already has code to fix this. We can simply use `components` to normalize the path so it works as intended.
-rw-r--r--compiler/rustc_expand/src/base.rs8
-rw-r--r--tests/run-make/import-macro-verbatim/include/include.txt1
-rw-r--r--tests/run-make/import-macro-verbatim/rmake.rs8
-rw-r--r--tests/run-make/import-macro-verbatim/verbatim.rs12
4 files changed, 28 insertions, 1 deletions
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index f0cfe133a49..bed500c3032 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,5 +1,6 @@
 use std::default::Default;
 use std::iter;
+use std::path::Component::Prefix;
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
 
@@ -1293,7 +1294,12 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
         base_path.push(path);
         Ok(base_path)
     } else {
-        Ok(path)
+        // This ensures that Windows verbatim paths are fixed if mixed path separators are used,
+        // which can happen when `concat!` is used to join paths.
+        match path.components().next() {
+            Some(Prefix(prefix)) if prefix.kind().is_verbatim() => Ok(path.components().collect()),
+            _ => Ok(path),
+        }
     }
 }
 
diff --git a/tests/run-make/import-macro-verbatim/include/include.txt b/tests/run-make/import-macro-verbatim/include/include.txt
new file mode 100644
index 00000000000..63d71b14c1d
--- /dev/null
+++ b/tests/run-make/import-macro-verbatim/include/include.txt
@@ -0,0 +1 @@
+static TEST: &str = "Hello World!";
diff --git a/tests/run-make/import-macro-verbatim/rmake.rs b/tests/run-make/import-macro-verbatim/rmake.rs
new file mode 100644
index 00000000000..d2bf626e0aa
--- /dev/null
+++ b/tests/run-make/import-macro-verbatim/rmake.rs
@@ -0,0 +1,8 @@
+//@ only-windows other platforms do not have Windows verbatim paths
+use run_make_support::rustc;
+fn main() {
+    // Canonicalizing the path ensures that it's verbatim (i.e. starts with `\\?\`)
+    let mut path = std::fs::canonicalize(file!()).unwrap();
+    path.pop();
+    rustc().input("verbatim.rs").env("VERBATIM_DIR", path).run();
+}
diff --git a/tests/run-make/import-macro-verbatim/verbatim.rs b/tests/run-make/import-macro-verbatim/verbatim.rs
new file mode 100644
index 00000000000..56a83673c1f
--- /dev/null
+++ b/tests/run-make/import-macro-verbatim/verbatim.rs
@@ -0,0 +1,12 @@
+//! Include a file by concating the verbatim path using `/` instead of `\`
+
+include!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
+fn main() {
+    assert_eq!(TEST, "Hello World!");
+
+    let s = include_str!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
+    assert_eq!(s, "static TEST: &str = \"Hello World!\";\n");
+
+    let b = include_bytes!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
+    assert_eq!(b, b"static TEST: &str = \"Hello World!\";\n");
+}