Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[beta] backports #117644

Merged
merged 4 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ pub mod assert_matches {
pub use crate::macros::{assert_matches, debug_assert_matches};
}

#[unstable(feature = "cfg_match", issue = "115585")]
pub use crate::macros::cfg_match;

#[macro_use]
mod internal_macros;

Expand Down
177 changes: 88 additions & 89 deletions library/core/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,94 @@ pub macro assert_matches {
},
}

/// A macro for defining `#[cfg]` match-like statements.
///
/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of
/// `#[cfg]` cases, emitting the implementation which matches first.
///
/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
/// without having to rewrite each clause multiple times.
///
/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when
/// all previous declarations do not evaluate to true.
///
/// # Example
///
/// ```
/// #![feature(cfg_match)]
///
/// cfg_match! {
/// cfg(unix) => {
/// fn foo() { /* unix specific functionality */ }
/// }
/// cfg(target_pointer_width = "32") => {
/// fn foo() { /* non-unix, 32-bit functionality */ }
/// }
/// _ => {
/// fn foo() { /* fallback implementation */ }
/// }
/// }
/// ```
#[unstable(feature = "cfg_match", issue = "115585")]
#[rustc_diagnostic_item = "cfg_match"]
pub macro cfg_match {
// with a final wildcard
(
$(cfg($initial_meta:meta) => { $($initial_tokens:item)* })+
_ => { $($extra_tokens:item)* }
) => {
cfg_match! {
@__items ();
$((($initial_meta) ($($initial_tokens)*)),)+
(() ($($extra_tokens)*)),
}
},

// without a final wildcard
(
$(cfg($extra_meta:meta) => { $($extra_tokens:item)* })*
) => {
cfg_match! {
@__items ();
$((($extra_meta) ($($extra_tokens)*)),)*
}
},

// Internal and recursive macro to emit all the items
//
// Collects all the previous cfgs in a list at the beginning, so they can be
// negated. After the semicolon is all the remaining items.
(@__items ($($_:meta,)*);) => {},
(
@__items ($($no:meta,)*);
(($($yes:meta)?) ($($tokens:item)*)),
$($rest:tt,)*
) => {
// Emit all items within one block, applying an appropriate #[cfg]. The
// #[cfg] will require all `$yes` matchers specified and must also negate
// all previous matchers.
#[cfg(all(
$($yes,)?
not(any($($no),*))
))]
cfg_match! { @__identity $($tokens)* }

// Recurse to emit all other items in `$rest`, and when we do so add all
// our `$yes` matchers to the list of `$no` matchers as future emissions
// will have to negate everything we just matched as well.
cfg_match! {
@__items ($($no,)* $($yes,)?);
$($rest,)*
}
},

// Internal macro to make __apply work out right for different match types,
// because of how macros match/expand stuff.
(@__identity $($tokens:item)*) => {
$($tokens)*
}
}

/// Asserts that a boolean expression is `true` at runtime.
///
/// This will invoke the [`panic!`] macro if the provided expression cannot be
Expand Down Expand Up @@ -321,95 +409,6 @@ pub macro debug_assert_matches($($arg:tt)*) {
}
}

/// A macro for defining `#[cfg]` match-like statements.
///
/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of
/// `#[cfg]` cases, emitting the implementation which matches first.
///
/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
/// without having to rewrite each clause multiple times.
///
/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when
/// all previous declarations do not evaluate to true.
///
/// # Example
///
/// ```
/// #![feature(cfg_match)]
///
/// cfg_match! {
/// cfg(unix) => {
/// fn foo() { /* unix specific functionality */ }
/// }
/// cfg(target_pointer_width = "32") => {
/// fn foo() { /* non-unix, 32-bit functionality */ }
/// }
/// _ => {
/// fn foo() { /* fallback implementation */ }
/// }
/// }
/// ```
#[macro_export]
#[unstable(feature = "cfg_match", issue = "115585")]
#[rustc_diagnostic_item = "cfg_match"]
macro_rules! cfg_match {
// with a final wildcard
(
$(cfg($initial_meta:meta) => { $($initial_tokens:item)* })+
_ => { $($extra_tokens:item)* }
) => {
cfg_match! {
@__items ();
$((($initial_meta) ($($initial_tokens)*)),)+
(() ($($extra_tokens)*)),
}
};

// without a final wildcard
(
$(cfg($extra_meta:meta) => { $($extra_tokens:item)* })*
) => {
cfg_match! {
@__items ();
$((($extra_meta) ($($extra_tokens)*)),)*
}
};

// Internal and recursive macro to emit all the items
//
// Collects all the previous cfgs in a list at the beginning, so they can be
// negated. After the semicolon is all the remaining items.
(@__items ($($_:meta,)*);) => {};
(
@__items ($($no:meta,)*);
(($($yes:meta)?) ($($tokens:item)*)),
$($rest:tt,)*
) => {
// Emit all items within one block, applying an appropriate #[cfg]. The
// #[cfg] will require all `$yes` matchers specified and must also negate
// all previous matchers.
#[cfg(all(
$($yes,)?
not(any($($no),*))
))]
cfg_match! { @__identity $($tokens)* }

// Recurse to emit all other items in `$rest`, and when we do so add all
// our `$yes` matchers to the list of `$no` matchers as future emissions
// will have to negate everything we just matched as well.
cfg_match! {
@__items ($($no,)* $($yes,)?);
$($rest,)*
}
};

// Internal macro to make __apply work out right for different match types,
// because of how macros match/expand stuff.
(@__identity $($tokens:item)*) => {
$($tokens)*
};
}

/// Returns whether the given expression matches any of the given patterns.
///
/// Like in a `match` expression, the pattern can be optionally followed by `if`
Expand Down
58 changes: 33 additions & 25 deletions src/bootstrap/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ fn sanitize_sh(path: &Path) -> String {
}

fn is_dir_writable_for_user(dir: &PathBuf) -> bool {
let tmp_file = dir.join(".tmp");
match fs::File::create(&tmp_file) {
let tmp = dir.join(".tmp");
match fs::create_dir_all(&tmp) {
Ok(_) => {
fs::remove_file(tmp_file).unwrap();
fs::remove_dir_all(tmp).unwrap();
true
}
Err(e) => {
Expand All @@ -73,16 +73,27 @@ fn install_sh(

let prefix = default_path(&builder.config.prefix, "/usr/local");
let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
let destdir_env = env::var_os("DESTDIR").map(PathBuf::from);

// Sanity check for the user write access on prefix and sysconfdir
assert!(
is_dir_writable_for_user(&prefix),
"User doesn't have write access on `install.prefix` path in the `config.toml`.",
);
assert!(
is_dir_writable_for_user(&sysconfdir),
"User doesn't have write access on `install.sysconfdir` path in `config.toml`."
);
// Sanity checks on the write access of user.
//
// When the `DESTDIR` environment variable is present, there is no point to
// check write access for `prefix` and `sysconfdir` individually, as they
// are combined with the path from the `DESTDIR` environment variable. In
// this case, we only need to check the `DESTDIR` path, disregarding the
// `prefix` and `sysconfdir` paths.
if let Some(destdir) = &destdir_env {
assert!(is_dir_writable_for_user(destdir), "User doesn't have write access on DESTDIR.");
} else {
assert!(
is_dir_writable_for_user(&prefix),
"User doesn't have write access on `install.prefix` path in the `config.toml`.",
);
assert!(
is_dir_writable_for_user(&sysconfdir),
"User doesn't have write access on `install.sysconfdir` path in `config.toml`."
);
}

let datadir = prefix.join(default_path(&builder.config.datadir, "share"));
let docdir = prefix.join(default_path(&builder.config.docdir, "share/doc/rust"));
Expand All @@ -96,13 +107,13 @@ fn install_sh(
let mut cmd = Command::new(SHELL);
cmd.current_dir(&empty_dir)
.arg(sanitize_sh(&tarball.decompressed_output().join("install.sh")))
.arg(format!("--prefix={}", prepare_dir(prefix)))
.arg(format!("--sysconfdir={}", prepare_dir(sysconfdir)))
.arg(format!("--datadir={}", prepare_dir(datadir)))
.arg(format!("--docdir={}", prepare_dir(docdir)))
.arg(format!("--bindir={}", prepare_dir(bindir)))
.arg(format!("--libdir={}", prepare_dir(libdir)))
.arg(format!("--mandir={}", prepare_dir(mandir)))
.arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix)))
.arg(format!("--sysconfdir={}", prepare_dir(&destdir_env, sysconfdir)))
.arg(format!("--datadir={}", prepare_dir(&destdir_env, datadir)))
.arg(format!("--docdir={}", prepare_dir(&destdir_env, docdir)))
.arg(format!("--bindir={}", prepare_dir(&destdir_env, bindir)))
.arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir)))
.arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir)))
.arg("--disable-ldconfig");
builder.run(&mut cmd);
t!(fs::remove_dir_all(&empty_dir));
Expand All @@ -112,19 +123,16 @@ fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf {
config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default))
}

fn prepare_dir(mut path: PathBuf) -> String {
fn prepare_dir(destdir_env: &Option<PathBuf>, mut path: PathBuf) -> String {
// The DESTDIR environment variable is a standard way to install software in a subdirectory
// while keeping the original directory structure, even if the prefix or other directories
// contain absolute paths.
//
// More information on the environment variable is available here:
// https://www.gnu.org/prep/standards/html_node/DESTDIR.html
if let Some(destdir) = env::var_os("DESTDIR").map(PathBuf::from) {
// Sanity check for the user write access on DESTDIR
assert!(is_dir_writable_for_user(&destdir), "User doesn't have write access on DESTDIR.");

if let Some(destdir) = destdir_env {
let without_destdir = path.clone();
path = destdir;
path = destdir.clone();
// Custom .join() which ignores disk roots.
for part in without_destdir.components() {
if let Component::Normal(s) = part {
Expand Down
2 changes: 1 addition & 1 deletion src/llvm-project
Submodule llvm-project updated 67 files
+4 −2 .github/workflows/release-tasks.yml
+1 −1 clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp
+3 −0 clang-tools-extra/clangd/TidyProvider.cpp
+18 −0 clang-tools-extra/test/clang-tidy/checkers/modernize/use-trailing-return-type-cxx20.cpp
+8 −1 clang/docs/ReleaseNotes.rst
+1 −1 clang/include/clang/Basic/DiagnosticASTKinds.td
+9 −4 clang/lib/AST/ExprConstant.cpp
+2 −1 clang/lib/AST/Interp/Interp.cpp
+1 −1 clang/lib/Format/WhitespaceManager.cpp
+9 −2 clang/lib/Parse/ParseDecl.cpp
+27 −0 clang/test/CodeGen/thread_local.c
+19 −0 clang/test/Sema/thread_local.c
+6 −0 clang/test/SemaCXX/constant-expression-cxx2a.cpp
+7 −0 clang/test/SemaCXX/eval-crashes.cpp
+0 −10 clang/unittests/Format/FormatTest.cpp
+9 −0 flang/lib/Optimizer/CodeGen/CodeGen.cpp
+41 −0 flang/test/Fir/comdat.fir
+7 −1 flang/test/Intrinsics/math-codegen.fir
+44 −16 libcxx/include/__config
+46 −0 libcxx/test/libcxx/odr_signature.exceptions.sh.cpp
+72 −0 libcxx/test/libcxx/odr_signature.hardening.sh.cpp
+1 −0 libcxx/test/std/input.output/string.streams/stringstream/stringstream.members/gcount.pass.cpp
+8 −0 libcxx/utils/libcxx/test/params.py
+1 −1 llvm/CMakeLists.txt
+1 −1 llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+24 −0 llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+3 −0 llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h
+5 −2 llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
+2 −0 llvm/lib/Target/LoongArch/LoongArch.h
+121 −0 llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
+17 −0 llvm/lib/Target/LoongArch/LoongArchFloat32InstrInfo.td
+12 −0 llvm/lib/Target/LoongArch/LoongArchFloatInstrFormats.td
+6 −0 llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp
+0 −7 llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
+1 −0 llvm/lib/Target/LoongArch/LoongArchTargetMachine.cpp
+14 −5 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+13 −3 llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+29 −39 llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+8 −3 llvm/lib/Transforms/Scalar/GVN.cpp
+1 −0 llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+29 −0 llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-tail-call-fallback.ll
+190 −0 llvm/test/CodeGen/AArch64/arg_promotion.ll
+22 −0 llvm/test/CodeGen/AArch64/framelayout-sve.mir
+1 −0 llvm/test/CodeGen/LoongArch/O0-pipeline.ll
+34 −0 llvm/test/CodeGen/LoongArch/cfr-copy.mir
+26 −0 llvm/test/CodeGen/LoongArch/cfr-pseudo-copy.mir
+6 −7 llvm/test/CodeGen/LoongArch/inline-asm-clobbers-fcc.mir
+1 −0 llvm/test/CodeGen/LoongArch/opt-pipeline.ll
+6 −0 llvm/test/CodeGen/RISCV/double-maximum-minimum.ll
+14 −0 llvm/test/CodeGen/RISCV/double-select-fcmp.ll
+15 −1 llvm/test/Transforms/ConstraintElimination/large-constant-ints.ll
+1 −1 llvm/test/Transforms/ConstraintElimination/shl.ll
+131 −2 llvm/test/Transforms/CorrelatedValuePropagation/abs.ll
+57 −0 llvm/test/Transforms/GVN/pr69301.ll
+14 −0 llvm/test/Transforms/MemCpyOpt/memcpy.ll
+1 −1 llvm/utils/gn/secondary/llvm/version.gni
+1 −1 llvm/utils/lit/lit/__init__.py
+26 −0 mlir/include/mlir/Dialect/LLVMIR/Transforms/AddComdats.h
+1 −0 mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.h
+13 −0 mlir/include/mlir/Dialect/LLVMIR/Transforms/Passes.td
+64 −0 mlir/lib/Dialect/LLVMIR/Transforms/AddComdats.cpp
+1 −0 mlir/lib/Dialect/LLVMIR/Transforms/CMakeLists.txt
+2 −1 mlir/lib/ExecutionEngine/CRunnerUtils.cpp
+17 −0 mlir/test/Dialect/LLVMIR/add-linkonce-comdat.mlir
+1 −2 openmp/libomptarget/tools/kernelreplay/llvm-omp-kernel-replay.cpp
+2 −1 openmp/runtime/src/kmp_runtime.cpp
+1 −1 openmp/runtime/src/kmp_wrapper_getpid.h
Loading